# WOKCommands Documentation

WOKCommands is a Discord.JS command handler created by the Worn Off Keys YouTube channel.

## Installation

To install the WOKCommands package run the following command in your terminal:

```bash
npm install wokcommands
```

If you are interested in the latest development build then use this command instead:

{% hint style="warning" %}
The latest build could contain bugs, please check the changelog frequently and report any bugs in the community Discord server (see "USEFUL LINKS").
{% endhint %}

```bash
npm install github:AlexzanderFlores/WOKCommands-v2
```

## 🧠 Build a website dashboard, monetize your bot, and get more users

Are you wanting to take your Discord bot to the next level? Check out our premium course with over 90 video tutorials:

[https://LevelUpYourBot.com](https://levelupyourbot.com)

## 💰 $100 in FREE Hosting Credits

Want the best server for your money? Check out this short tutorial:

<https://www.youtube.com/watch?v=BiT2Kc-kYeQ>

## 🙋‍♂️ Support Discord server

If you need help with this package then try asking in the official Worn Off Keys community Discord server:

<https://wornoffkeys.com/discord>

## 📺 YouTube Channel

Check out hundreds of Discord.JS programming tutorials here:

<https://youtube.com/WornOffKeys>


# Setup & Options object

Here is a basic example of how to setup WOKCommands. When calling the constructor you can pass in an options object that configures WOKCommands to how you want.

Here is a simple example with only the essentials to get a bot up and running:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="index.js" %}

```javascript
const { Client, IntentsBitField, Partials } = require("discord.js");
const WOK = require("wokcommands");
const path = require("path");
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  new WOK({
    client,
    commandsDir: path.join(__dirname, "commands"),
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="index.ts" %}

```typescript
import { Client, IntentsBitField, Partials } from "discord.js";
import WOK from "wokcommands";
import path from "path";
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  new WOK({
    client,
    commandsDir: path.join(__dirname, "commands"),
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}
{% endtabs %}

Here is a full example of all options:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="index.js" %}

```javascript
const { Client, IntentsBitField, Partials } = require("discord.js");
const WOK = require("wokcommands");
const path = require("path");
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  new WOK({
    // The client for your bot. This is the only required property
    client,
    // Path to your commands folder
    commandsDir: path.join(__dirname, "commands"),
    // Path to your features folder
    featuresDir: path.join(__dirname, "features"),
    // Configure your event handlers
    events: {
      // Where your events are located. This is required if you
      // provide this events object
      dir: path.join(__dirname, "events"),
      // To learn how to properly configure your events please see
      // https://docs.wornoffkeys.com/events/what-is-a-feature
    },
    // Your MongoDB connection URI
    mongoUri: process.env.MONGO_URI || '',
    // What server IDs are for testing. This is where test
    // only commands are registered to
    testServers: ["TEST_SERVER_ID_HERE"],
    // User IDs who are bot owners/developers. These users
    // can access owner only commands
    botOwners: ["YOUR_DISCORD_ID_HERE"],
    // Don't want some of the default commands? Add them here
    disabledDefaultCommands: [
      // DefaultCommands.ChannelCommand,
      // DefaultCommands.CustomCommand,
      // DefaultCommands.Prefix,
      // DefaultCommands.RequiredPermissions,
      // DefaultCommands.RequiredRoles,
      // DefaultCommands.ToggleCommand
    ],
    // Configure the cooldowns for your commands and features
    cooldownConfig: {
      errorMessage: "Please wait {TIME} before doing that again.",
      botOwnersBypass: false,
      // The amount of seconds required for a cooldown to be
      // persistent via MongoDB.
      dbRequired: 300,
    },
    // Dynamic validations
    validations: {
      // Syntax based validations: Ran per command whenever
      // the bot starts up. Useful to throw errors if the
      // syntax of a command is not correct.
      syntax: path.join(__dirname, "validations", "syntax"),
      // Runtime based validations: Ran per command whenever
      // that command is ran. Should return true or false
      // depending on if the command should be ran or not.
      runtime: path.join(__dirname, "validations", "runtime"),
      // For more information on how to configure dyanmic validations
      // please see: TODO: add link
    }
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="index.ts" %}

```typescript
import { Client, IntentsBitField, Partials } from "discord.js";
import WOK from "wokcommands";
import path from "path";
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  new WOK({
    // The client for your bot. This is the only required property
    client,
    // Path to your commands folder
    commandsDir: path.join(__dirname, "commands"),
    // Path to your features folder
    featuresDir: path.join(__dirname, "features"),
    // Configure your event handlers
    events: {
      // Where your events are located. This is required if you
      // provide this events object
      dir: path.join(__dirname, "events"),
      // To learn how to properly configure your events please see
      // https://docs.wornoffkeys.com/events/what-is-a-feature
    },
    // Your MongoDB connection URI
    mongoUri: process.env.MONGO_URI || '',
    // What server IDs are for testing. This is where test
    // only commands are registered to
    testServers: ["TEST_SERVER_ID_HERE"],
    // User IDs who are bot owners/developers. These users
    // can access owner only commands
    botOwners: ["YOUR_DISCORD_ID_HERE"],
    // Don't want some of the default commands? Add them here
    disabledDefaultCommands: [
      // DefaultCommands.ChannelCommand,
      // DefaultCommands.CustomCommand,
      // DefaultCommands.Prefix,
      // DefaultCommands.RequiredPermissions,
      // DefaultCommands.RequiredRoles,
      // DefaultCommands.ToggleCommand
    ],
    // Configure the cooldowns for your commands and features
    cooldownConfig: {
      errorMessage: "Please wait {TIME} before doing that again.",
      botOwnersBypass: false,
      // The amount of seconds required for a cooldown to be
      // persistent via MongoDB.
      dbRequired: 300,
    },
    // Dynamic validations
    validations: {
      // Syntax based validations: Ran per command whenever
      // the bot starts up. Useful to throw errors if the
      // syntax of a command is not correct.
      syntax: path.join(__dirname, "validations", "syntax"),
      // Runtime based validations: Ran per command whenever
      // that command is ran. Should return true or false
      // depending on if the command should be ran or not.
      runtime: path.join(__dirname, "validations", "runtime"),
      // For more information on how to configure dyanmic validations
      // please see: TODO: add link
    }
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}
{% endtabs %}


# Ping pong command example

{% embed url="<https://youtu.be/_67r4wq23BA?t=31>" %}

WOKCommands is easy to get setup and working. On this page you will learn how to create a simple "Ping -> Pong" command.

First you must setup WOKCommands in your main file:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="index.js" %}

```javascript
const { Client, IntentsBitField, Partials } = require("discord.js");
const WOK = require("wokcommands");
const path = require("path");
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  new WOK({
    client,
    commandsDir: path.join(__dirname, "commands"),
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="index.ts" %}

```typescript
import { Client, IntentsBitField, Partials } from "discord.js";
import WOK from "wokcommands";
import path from "path";
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  new WOK({
    client,
    commandsDir: path.join(__dirname, "commands"),
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}
{% endtabs %}

Then create a "commands" folder where you can create a "ping.js" file with the following contents:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="ping.js" %}

```javascript
const { CommandType } = require("wokcommands");

module.exports = {
  // Required for slash commands
  description: "Ping pong command",
  
  // Create a legacy and slash command
  type: CommandType.BOTH,

  // Invoked when a user runs the ping command
  callback: () => {
    // Return the same object you would use in
    // message.reply
    // or
    // interaction.reply
    // WOKCommands will reply to the message or the interaction
    // depending on how the user ran the command (legacy vs slash)
    return {
      content: "Pong!",
    }
  },
}
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="ping.ts" %}

```typescript
import { CommandObject, CommandType } from "wokcommands";

export default {
  // Required for slash commands
  description: "Ping pong command",
  
  // Create a legacy and slash command
  type: CommandType.BOTH,

  // Invoked when a user runs the ping command
  callback: () => {
    // Return the same object you would use in
    // message.reply
    // or
    // interaction.reply
    // WOKCommands will reply to the message or the interaction
    // depending on how the user ran the command (legacy vs slash)
    return {
      content: "Pong!",
    }
  },
} as CommandObject
```

{% endcode %}
{% endtab %}
{% endtabs %}

After inviting your bot to a Discord server and running `!ping` ("!" is the default command prefix) or `/ping`, your bot should reply with `Pong!`.


# Command properties

{% embed url="<https://youtu.be/_67r4wq23BA?t=146>" %}

This page assumes you have a basic bot running using WOKCommands as seen [here](https://docs.wornoffkeys.com/commands/ping-pong-command-example).

{% hint style="info" %}
A command's file name will become the executable name of the command. Additional aliases can be set.
{% endhint %}

{% hint style="danger" %}
This code is designed for demonstration purposes only. Copy/pasting this will lead to errors.
{% endhint %}

## Object properties

All commands are exported as objects who have properties to dictate the command's functionality. Here is a complete list of all current properties available to you:

{% tabs %}
{% tab title="JavaScript" %}

```javascript
module.exports = {
    // REQUIRED
    // This function will be invoked when users run this command
    callback: ({
        // An instance of your bot's client
        client,
        // An instance of WOKCommands
        instance,
        // The message used for legacy commands. This is null
        // if the user ran this command as a slash command
        message,
        // The interaction used for slash commands. This is null
        // if the user ran this command as a legacy commands
        interaction,
        // Each argument sent with this command. For legacy commands
        // each word is treated as an argument
        args,
        // All of the arguments joined together into one string
        text,
        // The guild where this command was ran
        guild,
        // The memebr who ran this command
        member,
        // The user who ran this command
        user,
        // The channel where this command was ran
        channel,
        // A method run cancel a cooldown
        cancelCooldown,
        // A method to update a cooldown experation date
        updateCooldown,
    }) => {
        // TODO: Return an object or string that will be sent in
        // either message.reply or interaction.reply
        // depending on how the user ran this command
    },
    
    // REQUIRED
    // What type of command this is. Options:
    // LEGACY
    // SLASH
    // BOTH
    type: CommandType.BOTH,
    
    // A method that is invoked when the command is first registered
    // Perfect for pulling information from a database
    init: (client, instance) => {},
    
    // REQUIRED IF THIS COMMAND IS A "SLASH" OR "BOTH" TYPE
    // Sets the description for this command
    description: "Add your description here",
    
    // What other aliases should this command have as a legacy command
    aliases: [],
    
    // If this command should only be registered for test servers
    testOnly: false,
    
    // If this command should only be ran within guilds/servers
    guildOnly: false,
    
    // If this command should only be ran by bot owners/developers
    // NOTE: This has nothing to do with guild/server owners
    ownerOnly: false,
    
    // What build in Discord permissions are required to use this command
    permissions: [],
    
    // If this slash command should be defered. Options:
    // "ephemeral" // Creates an ephemeral reply that is deferred
    // true // Creates a publicly visible reply that is deferred
    // false // Default value
    deferReply: false,
    
    // Customize how cooldowns work for this command
    cooldowns: {
        // Custom error message for this command
        errorMessage: "Please wait {TIME}",
        
        // You MUST select ONE of the following:
        // Applies a cooldown to a specific user over all guilds and DMs
        perUser: 10, // Example of 10 seconds
        // Applies a cooldown to a specific user in a specific guild
        perUserPerGuild: "10 s", // Example of 10 seconds
        // Applies a cooldown to all users in a specific guild
        perGuild: "10 h", // Example of 10 hours
        global: "1 d", // Example of 1 day
    },
    
    // What the minimum amount of arguments are. Used for legacy commands
    // or slash commands when you don't provide an options array
    minArgs: 0,
    
    // What the maximum amount of arguments are. Used for legacy commands
    // or slash commands when you don't provide an options array.
    // -1 = unlimited arguments
    maxArgs: -1,
    
    // The message to be sent if the user doesn't provide the correct syntax
    correctSyntax: "Correct syntax: {PREFIX}{COMMAND} {ARGS}",
    
    // The exact arguments the user is expecting to enter. This is used for
    // the "{ARGS}" in the "correctSyntax". If you do not provide an options
    // array then your slash command arguments are created using this string.
    // Example for an "!add 5 10" command:
    // expectedArgs: "[num1] [num2]"
    // Another syntax:
    expectedArgs: "<num1> <num2>",
    
    // An array of https://discord.js.org/#/docs/discord.js/main/typedef/ApplicationCommandOption
    options: [],
    
    // This function is invoked when autocomplete is ran in this command.
    // To enable autocomplete pass in an options array with "autocomplete: true"
    autocomplete: (command, argument, instance) => {
        // TODO: Return an array of strings
    },
    
    // If message.reply() vs message.channel.send() should be used for
    // legacy commands
    reply: true,
    
    // Delete this command as both a legacy and slash command
    // This will delete the "testOnly" or "global" version of this slash
    // command. For example: testOnly = true && delete = true then this slash
    // command will be deleted in the test servers only. However testOnly = false
    // means the global slash command will be deleted.
    delete: false
}
```

{% endtab %}

{% tab title="TypeScript" %}

```typescript
export default {
    // REQUIRED
    // This function will be invoked when users run this command
    callback: ({
        // An instance of your bot's client
        client: Client,
        // An instance of WOKCommands
        instance: WOKCommands,
        // The message used for legacy commands. This is null
        // if the user ran this command as a slash command
        message: Message,
        // The interaction used for slash commands. This is null
        // if the user ran this command as a legacy commands
        interaction: Interaction,
        // Each argument sent with this command. For legacy commands
        // each word is treated as an argument
        args: string[],
        // All of the arguments joined together into one string
        text: string,
        // The guild where this command was ran
        guild: Guild | null,
        // The memebr who ran this command
        member: Member | null,
        // The user who ran this command
        user: User,
        // The channel where this command was ran
        channel: TextChannel,
        // A method run cancel a cooldown
        cancelCooldown: () => {},
        // A method to update a cooldown experation date
        updateCooldown: (expires: Date) => {},
    }) => {
        // TODO: Return an object or string that will be sent in
        // either message.reply or interaction.reply
        // depending on how the user ran this command
    },
    
    // REQUIRED
    // What type of command this is. Options:
    // LEGACY
    // SLASH
    // BOTH
    type: CommandType.BOTH,
    
    // A method that is invoked when the command is first registered
    // Perfect for pulling information from a database
    init: (client: Client, instance: WOKCommands) => {},
    
    // REQUIRED IF THIS COMMAND IS A "SLASH" OR "BOTH" TYPE
    // Sets the description for this command
    description: "Add your description here",
    
    // What other aliases should this command have as a legacy command
    aliases: [],
    
    // If this command should only be registered for test servers
    testOnly: false,
    
    // If this command should only be ran within guilds/servers
    guildOnly: false,
    
    // If this command should only be ran by bot owners/developers
    // NOTE: This has nothing to do with guild/server owners
    ownerOnly: false,
    
    // What build in Discord permissions are required to use this command
    permissions: [],
    
    // If this slash command should be defered. Options:
    // "ephemeral" // Creates an ephemeral reply that is deferred
    // true // Creates a publicly visible reply that is deferred
    // flase // Default value
    deferReply: false,
    
    // Customize how cooldowns work for this command
    cooldowns: {
        // Custom error message for this command
        errorMessage: "Please wait {TIME}",
        
        // You MUST select ONE of the following:
        // Applies a cooldown to a specific user over all guilds and DMs
        perUser: 10, // Example of 10 seconds
        // Applies a cooldown to a specific user in a specific guild
        perUserPerGuild: "10 s", // Example of 10 seconds
        // Applies a cooldown to all users in a specific guild
        perGuild: "10 h", // Example of 10 hours
        global: "1 d", // Example of 1 day
    },
    
    // What the minimum amount of arguments are. Used for legacy commands
    // or slash commands when you don't provide an options array
    minArgs: 0,
    
    // What the maximum amount of arguments are. Used for legacy commands
    // or slash commands when you don't provide an options array.
    // -1 = unlimited arguments
    maxArgs: -1,
    
    // The message to be sent if the user doesn't provide the correct syntax
    correctSyntax: "Correct syntax: {PREFIX}{COMMAND} {ARGS}",
    
    // The exact arguments the user is expecting to enter. This is used for
    // the "{ARGS}" in the "correctSyntax". If you do not provide an options
    // array then your slash command arguments are created using this string.
    // Example for an "!add 5 10" command:
    // expectedArgs: "[num1] [num2]"
    // Another syntax:
    expectedArgs: "<num1> <num2>",
    
    // An array of https://discord.js.org/#/docs/discord.js/main/typedef/ApplicationCommandOption
    options: [],
    
    // This function is invoked when autocomplete is ran in this command.
    // To enable autocomplete pass in an options array with "autocomplete: true"
    autocomplete: (command: Command, argument: string, instance: WOKCommands) => {
        // TODO: Return an array of strings
    },
    
    // If message.reply() vs message.channel.send() should be used for
    // legacy commands
    reply: true,
    
    // Delete this command as both a legacy and slash command
    // This will delete the "testOnly" or "global" version of this slash
    // command. For example: testOnly = true && delete = true then this slash
    // command will be deleted in the test servers only. However testOnly = false
    // means the global slash command will be deleted.
    delete: false
} as CommandObject
```

{% endtab %}
{% endtabs %}


# Correct argument usage

{% embed url="<https://youtu.be/_67r4wq23BA?t=254>" %}

You can specify the exact arguments and the minimum/maximum number of arguments for each command. If the user provides an incorrect number of arguments then WOKCommands will automatically tell them the correct usage based off of the command properties you provided. Here is an example:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="add.js" %}

```javascript
import { CommandType } from "wokcommands";

module.exports = {
  description: "Adds numbers together",
  type: CommandType.BOTH,

  minArgs: 2,
  maxArgs: 2,
  expectedArgs: "<num1> <num2>",

  callback: ({ args }) => {
    const sum = args.reduce((acc, cur) => {
      return acc + Number(cur)
    }, 0)

    return `The sum is ${sum}`
  },
}
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="add.ts" %}

```typescript
import { CommandType, CommandObject, CommandUsage } from "wokcommands";

export default {
  description: "Adds numbers together",
  type: CommandType.BOTH,

  minArgs: 2,
  maxArgs: 2,
  expectedArgs: "<num1> <num2>",;

  callback: (options: CommandUsage) => {
    const { args } = options

    const sum = args.reduce((acc, cur) => {
      return acc + Number(cur)
    }, 0)

    return `The sum is ${sum}`
  },
} as CommandObject;
```

{% endcode %}
{% endtab %}
{% endtabs %}

If the user runs `!add` or `!add 5` your bot will respond with `Correct syntax: !add <num1> <num2>`. If the user runs `!add 5 10` it will then respond with `The sum is 15`.


# Command initialization method

{% embed url="<https://youtu.be/_67r4wq23BA?t=402>" %}

Some commands may require you to run code when they are loaded. You can use the `init()` method within your command to handle this type of functionality:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="ping.js" %}

```javascript
const { CommandType } = require("wokcommands");

module.exports = {
  description: "Ping pong command",
  type: CommandType.BOTH,

  init: (client, instance) => {
    console.log("Ping command has been loaded");
  },

  callback: () => {
    return {
      content: "Pong!",
    };
  },
};
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="ping.ts" %}

```typescript
import { Client } from "discord.js";
import WOKCommands, { CommandObject, CommandType } from "wokcommands";

export default {
  description: "Ping pong command",
  type: CommandType.BOTH,

  init: (client: Client, instance: WOKCommands) => {
    console.log("Ping command has been loaded");
  },

  callback: () => {
    return {
      content: "Pong!",
    };
  },
} as CommandObject;
```

{% endcode %}
{% endtab %}
{% endtabs %}


# Bot owner only commands

{% embed url="<https://youtu.be/_67r4wq23BA?t=512>" %}

Some commands should only be available to the bot owners. A perfect example of this is a "status" command that updates the status of your bot. WOKCommands comes with this capability.

Here is how your command file should be setup:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="status.js" %}

```javascript
const { CommandType } = require("wokcommands");

const setStatus = (client, status) => {
  client.user?.setPresence({
    status: "online",
    activities: [
      {
        name: status,
        type: ActivityType.Playing,
      },
    ],
  });
};

module.exports = {
  description: "Sets the bot's status",

  type: CommandType.BOTH,

  minArgs: 1,
  expectedArgs: "<status>",

  ownerOnly: true,

  callback: ({ client, text }) => {
    setStatus(client, text);

    return {
      content: `Set status to "${text}"`,
    };
  },
};
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="status.ts" %}

```typescript
import { ActivityType, Client } from "discord.js";
import { CommandObject, CommandType, CommandUsage } from "wokcommands";

const setStatus = (client: Client, status: string) => {
  client.user?.setPresence({
    status: "online",
    activities: [
      {
        name: status,
        type: ActivityType.Playing,
      },
    ],
  });
};

export default {
  description: "Sets the bot's status",

  type: CommandType.BOTH,

  minArgs: 1,
  expectedArgs: "<status>",

  ownerOnly: true,

  callback: (options: CommandUsage) => {
    const { client, text } = options;
    setStatus(client, text);

    return {
      content: `Set status to "${text}"`,
    };
  },
} as CommandObject;
```

{% endcode %}
{% endtab %}
{% endtabs %}

Whenever we initialize WOKCommands we can pass in any number of IDs for the owner's Discord accounts:

{% hint style="info" %}
The bot owner's ID is automatically added to the bot owner list. If you are the only developer working on your project you do not need to add your ID.
{% endhint %}

{% tabs %}
{% tab title="JavaScript" %}
{% code title="index.js" %}

```javascript
const path = require("path");
const WOK = require("wokcommands");
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  console.log("The bot is ready");

  new WOK({
    client,
    commandsDir: path.join(__dirname, "commands"),
    botOwners: ["Your_ID_Here"]
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="index.ts" %}

```typescript
import { Client, IntentsBitField, Partials } from "discord.js";
import path from "path";
import WOK from "wokcommands";
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  console.log("The bot is ready");

  new WOK({
    client,
    commandsDir: path.join(__dirname, "commands"),
    botOwners: ["Your_ID_Here"]
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}
{% endtabs %}


# Test servers

{% embed url="<https://youtu.be/_67r4wq23BA?t=543>" %}

You may want some commands to only be enabled in specific servers/guilds for testing. This will give you a good idea if something is working in a production environment without risking bugs for your other users.

You can easily specify a command as a "test only" command like so:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="ping.js" %}

```javascript
const { CommandType } = require("wokcommands");

module.exports = {
  description: "Ping pong command",

  type: CommandType.BOTH,

  testOnly: true,

  callback: () => {
    return {
      content: "Pong!",
    };
  },
};
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="ping.ts" %}

```typescript
const { CommandType } = require("wokcommands");

module.exports = {
  description: "Ping pong command",

  type: CommandType.BOTH,

  testOnly: true,

  callback: () => {
    return {
      content: "Pong!",
    };
  },
};
```

{% endcode %}
{% endtab %}
{% endtabs %}

You can then specify any amount of server/guild IDs when initializing WOKCommands like so:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="index.js" %}

```javascript
const path = require("path");
const WOK = require("wokcommands");
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  console.log("The bot is ready");

  new WOK({
    client,
    commandsDir: path.join(__dirname, "commands"),
    testServers: ["Server_id_here"],
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="index.ts" %}

```typescript
import { Client, IntentsBitField, Partials } from "discord.js";
import path from "path";
import WOK from "wokcommands";
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  console.log("The bot is ready");

  new WOK({
    client,
    commandsDir: path.join(__dirname, "commands"),
    testServers: ["Server_id_here"],
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}
{% endtabs %}


# Cooldowns

{% embed url="<https://youtu.be/_67r4wq23BA?t=329>" %}

You can use command cooldowns to ensure your commands are only ran every so often. Each cooldown type requires a string for it's duration and duration type (seconds, minutes, etc)

| Character | Duration | Example |
| --------- | -------- | ------- |
| s         | Seconds  | 30 s    |
| m         | Minutes  | 10 m    |
| h         | Hours    | 5 h     |
| d         | Days     | 3 d     |

There are 4 types of cooldowns:

<table><thead><tr><th width="191">Cooldown Type</th><th>Description</th></tr></thead><tbody><tr><td>perUser</td><td>Applies to a specific user across all guilds and DMs</td></tr><tr><td>perUserPerGuild</td><td>Applies to a specific user in a specific guild</td></tr><tr><td>perGuild</td><td>Applies to all users in a specific guild</td></tr><tr><td>global</td><td>Applies to all users in all guilds</td></tr></tbody></table>

Example of per-user cooldowns:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="daily.js" %}

```javascript
const { CommandType, CooldownTypes } = require("wokcommands");

module.exports = {
  description: "Ping pong command",

  type: CommandType.BOTH,

  cooldowns: {
    type: CooldownTypes.perUser,
    duration: "1 d",
  },

  callback: () => {
    return {
      content: "Pong!",
    };
  },
};
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="daily.ts" %}

```typescript
import { CommandObject, CommandType, CooldownTypes } from "wokcommands";

export default {
  description: "Ping pong command",

  type: CommandType.BOTH,

  cooldowns: {
    type: CooldownTypes.perUser,
    duration: "1 d",
  },

  callback: () => {
    return {
      content: "Pong!",
    };
  },
} as CommandObject;
```

{% endcode %}
{% endtab %}
{% endtabs %}


# Required permissions

{% embed url="<https://youtu.be/_67r4wq23BA?t=320>" %}

You may want your commands to only be ran by users who have specific Discord permissions. This is often useful for administration commands.

Using WOKCommands you can easily specify what Discord permissions users need to run the command:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="ping.js" %}

```javascript
const { PermissionFlagsBits } = require("discord.js");
const { CommandType } = require("wokcommands");

module.exports = {
  description: "Ping pong command",

  type: CommandType.BOTH,

  permissions: [PermissionFlagsBits.Administrator],

  callback: () => {
    return {
      content: "Pong!",
    };
  },
};
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="ping.ts" %}

```typescript
import { PermissionFlagsBits } from "discord.js";
import { CommandObject, CommandType, CooldownTypes } from "wokcommands";

export default {
  description: "Ping pong command",

  type: CommandType.BOTH,

  permissions: [PermissionFlagsBits.Administrator],

  callback: () => {
    return {
      content: "Pong!",
    };
  },
} as CommandObject;
```

{% endcode %}
{% endtab %}
{% endtabs %}


# Slash commands

Slash commands are a new system for commands within Discord bots. WOKCommands aims to help developers implement slash commands in the easiest way possible.

Here is a basic ping pong slash command example:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="ping.js" %}

```javascript
import { CommandType } from "wokcommands";

export default {
  description: "Ping pong command",

  // Only create a slash command, not a legacy command
  // You can also use "CommandType.BOTH" to create a
  // legacy and slash command
  type: CommandType.SLASH,

  callback: () => {
    return {
      content: "Pong!",
      ephemeral: true,
    };
  },
};
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="ping.ts" %}

```typescript
import { CommandObject, CommandType } from "wokcommands";

export default {
  description: "Ping pong command",

  // Only create a slash command, not a legacy command
  // You can also use "CommandType.BOTH" to create a
  // legacy and slash command
  type: CommandType.SLASH,
  
  callback: () => {
    return {
      content: "Pong!",
      ephemeral: true,
    };
  },
} as CommandObject;
```

{% endcode %}
{% endtab %}
{% endtabs %}

When running `/ping` it will send "pong" in the same channel.

All of the normal WOKCommands callback arguments are available aside from `message`. A full list can be found [here](https://docs.wornoffkeys.com/commands/commands).

## Using your own Options for Slash Commands

{% embed url="<https://youtu.be/_67r4wq23BA?t=417>" %}

Sometimes you may want to pass in your own options object to your slash command. You can easily do so by passing in an `options` property to your command like so:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="add.js" %}

```javascript
module.exports = {
  category: 'test', // Required for the slash commands
  description: 'Adds two numbers', // Required for the slash commands

  slash: true, // If options are given then slash must be either true or 'both'
  testOnly: true, // Ensure you have test servers setup

  options: [
    {
      name: 'num1', // Must be lower case
      description: 'The first number.',
      required: true,
      type: 'STRING',
    },
    {
      name: 'num2', // Must be lower case
      description: 'The second number.',
      required: true,
      type: 'STRING',
    },
  ],
  callback: ({ interaction, args }) => {
    const num1 = parseInt(args[0])
    const num2 = parseInt(args[1])

    if (interaction) {
      interaction.reply({
        content: String(num1 + num2),
      })
    }
  },
}
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="add.ts" %}

```typescript
```

{% endcode %}
{% endtab %}
{% endtabs %}


# Inferred slash command arguments

Slash commands handle arguments differently, however WOKCommands will allow you to specify your slash command arguments in the same way as normal commands.

{% tabs %}
{% tab title="JavaScript" %}
{% code title="add.js" %}

```javascript
const { CommandType, CommandObject, CommandUsage } = require("wokcommands");

module.exports = {
  description: "Adds numbers together",

  // Only register a slash command, not a legacy command
  type: CommandType.SLASH,

  minArgs: 2,
  maxArgs: 2,
  expectedArgs: "<num1> <num2>",

  callback: ({ args }) => {
    const sum = args.reduce((acc, cur) => {
      return acc + Number(cur);
    }, 0);

    return `The sum is ${sum}`;
  },
};
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="add.ts" %}

```typescript
import { CommandType, CommandObject, CommandUsage } from "wokcommands";

export default {
  description: "Adds numbers together",

  // Only register a slash command, not a legacy command
  type: CommandType.SLASH,

  minArgs: 2,
  maxArgs: 2,
  expectedArgs: "<num1> <num2>",

  callback: (options: CommandUsage) => {
    const { args } = options;

    const sum = args.reduce((acc, cur) => {
      return acc + Number(cur);
    }, 0);

    return `The sum is ${sum}`;
  },
} as CommandObject
```

{% endcode %}
{% endtab %}
{% endtabs %}

Behind the scenes WOKCommands will create an array of [options](https://discord.js.org/#/docs/discord.js/main/typedef/ApplicationCommandOption) for your slash commands. As  you will see in the next section you can always customize these options if need be.

{% hint style="warning" %}
When using inferred arguments with slash commands, it's very important that you provide `minArgs` and `expectedArgs` properties.
{% endhint %}


# Custom slash command arguments

Sometimes you may want to pass in your own [options](https://discord.js.org/#/docs/discord.js/main/typedef/ApplicationCommandOption) objects to your slash command. This gives you more control over the exact details of your arguments.

{% tabs %}
{% tab title="JavaScript" %}
{% code title="add.js" %}

```javascript
const { ApplicationCommandOptionType } = require("discord.js");
const { CommandType } = require("wokcommands");

module.exports = {
  description: "Adds numbers together",

  // Create a legacy and slash command
  type: CommandType.BOTH,

  // An array of
  // https://discord.js.org/#/docs/discord.js/main/typedef/ApplicationCommandOption
  options: [
    {
      name: "num1",
      description: "The first number",
      type: ApplicationCommandOptionType.Number,
      required: true,
    },
    {
      name: "num2",
      description: "The second number",
      type: ApplicationCommandOptionType.Number,
      required: true,
    },
  ],

  callback: ({ args }) => {
    const sum = args.reduce((acc, cur) => {
      return acc + Number(cur);
    }, 0);

    return `The sum is ${sum}`;
  },
};
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="add.ts" %}

```typescript
import { ApplicationCommandOptionType } from "discord.js";
import { CommandType, CommandObject, CommandUsage } from "wokcommands";

export default {
  description: "Adds numbers together",

  // Create a legacy and slash command
  type: CommandType.BOTH,

  // An array of
  // https://discord.js.org/#/docs/discord.js/main/typedef/ApplicationCommandOption
  options: [
    {
      name: "num1",
      description: "The first number",
      type: ApplicationCommandOptionType.Number,
      required: true,
    },
    {
      name: "num2",
      description: "The second number",
      type: ApplicationCommandOptionType.Number,
      required: true,
    },
  ],

  callback: (options: CommandUsage) => {
    const { args } = options;

    const sum = args.reduce((acc, cur) => {
      return acc + Number(cur);
    }, 0);

    return `The sum is ${sum}`;
  },
} as CommandObject;
```

{% endcode %}
{% endtab %}
{% endtabs %}

The options array in this code snippet is similar to what WOKCommands will auto generate from the code in [Inferred slash command arguments](/commands/inferred-slash-command-arguments).


# Autocomplete

{% embed url="<https://youtu.be/_67r4wq23BA?t=466>" %}

WOKCommands comes with built in autocomplete handling for slash commands. As of now you must provide custom slash command options and not use inferred arguments.

{% tabs %}
{% tab title="JavaScript" %}
{% code title="os.js" %}

```javascript
const { ApplicationCommandOptionType } = require("discord.js");
const { CommandType } = require("wokcommands");

module.exports = {
  description: "Sets your operating system",
  type: CommandType.SLASH,

  options: [
    {
      name: "operating-system",
      description: "The operating system you use",
      type: ApplicationCommandOptionType.String,
      required: true,
      // Required for autocomplete to work
      autocomplete: true,
    },
  ],

  autocomplete: (command, argument, interaction) => {
    // Easier to view the autocomplete functionality with
    // two versions of Windows
    return ["Windows 10", "Windows 11", "Mac", "Linux"];
  },

  callback: ({ text }) => {
    return {
      content: `Your operating system is ${text}`,
      ephemeral: true,
    };
  },
};
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="os.ts" %}

```typescript
import {
  ApplicationCommandOptionType,
  AutocompleteInteraction,
} from "discord.js";
import { CommandObject, CommandType, CommandUsage } from "wokcommands";
import Command from "wokcommands/src/command-handler/Command";

export default {
  description: "Sets your operating system",
  type: CommandType.SLASH,

  options: [
    {
      name: "operating-system",
      description: "The operating system you use",
      type: ApplicationCommandOptionType.String,
      required: true,
      // Required for autocomplete to work
      autocomplete: true,
    },
  ],

  autocomplete: (
    command: Command,
    argument: string,
    interaction: AutocompleteInteraction
  ) => {
    // Easier to view the autocomplete functionality with
    // two versions of Windows
    return ["Windows 10", "Windows 11", "Mac", "Linux"];
  },

  callback: (options: CommandUsage) => {
    const { text } = options;

    return {
      content: `Your operating system is ${text}`,
      ephemeral: true,
    };
  },
} as CommandObject;
```

{% endcode %}
{% endtab %}
{% endtabs %}


# Validation setup

{% embed url="<https://youtu.be/_67r4wq23BA?t=571>" %}

There are two types of validations:

* Runtime validations
  * Ran against a command when it is used
  * Should return a true or false for if the command should be ran
  * You must provide any error messages if need be
  * Arguments:
    * command: Command
    * usage: CommandUsage
    * prefix: string
* Syntax validations
  * Ran against every command when your bot starts up
  * Should throw an error if the syntax for your command is wrong
  * Arguments:
    * command: Command

Here is an example of setting up your validations in your main file:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="index.js" %}

```javascript
const { Client, IntentsBitField, Partials } = require("discord.js");
const path = require("path");
const WOK = require("wokcommands");
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  console.log("The bot is ready");

  new WOK({
    client,
    mongoUri: process.env.MONGO_URI || "",
    commandsDir: path.join(__dirname, "commands"),
    validations: {
      // Where your runtime validation folder is
      runtime: path.join(__dirname, "validations", "runtime"),
      // Where your syntax validation folder is
      syntax: path.join(__dirname, "validations", "syntax"),
    },
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="index.ts" %}

```typescript
import { Client, IntentsBitField, Partials } from "discord.js";
import path from "path";
import WOK from "wokcommands";
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  console.log("The bot is ready");

  new WOK({
    client,
    mongoUri: process.env.MONGO_URI || "",
    commandsDir: path.join(__dirname, "commands"),
    validations: {
      // Where your runtime validation folder is
      runtime: path.join(__dirname, "validations", "runtime"),
      // Where your syntax validation folder is
      syntax: path.join(__dirname, "validations", "syntax"),
    },
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}
{% endtabs %}


# Runtime validations

{% embed url="<https://youtu.be/_67r4wq23BA?t=599>" %}

You can provide your own runtime validations methods that will return a boolean for if the command should actually be ran or not.

{% tabs %}
{% tab title="JavaScript" %}
{% code title="command-starts-with-a.js" %}

```javascript
module.exports = (command, usage, prefix) => {
  return command.commandName.startsWith("a");
};
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="command-starts-with-a.js" %}

```typescript
import { CommandUsage, Command } from "wokcommands";

export default (command: Command, usage: CommandUsage, prefix: string) => {
  return command.commandName.startsWith("a");
};
```

{% endcode %}
{% endtab %}
{% endtabs %}


# Syntax validations

{% embed url="<https://youtu.be/_67r4wq23BA?t=622>" %}

You can provide your own syntax validations that will be ran against every command. This function should throw an error if the syntax is incorrect.

{% hint style="info" %}
Callback functions will be checked by WOKCommands automatically. There is no need to actually implement this functionality yourself.
{% endhint %}

{% tabs %}
{% tab title="JavaScript" %}
{% code title="no-callback.js" %}

```javascript
module.exports = (command) => {
  const { commandObject, commandName } = command;

  if (!commandObject.callback) {
    throw new Error(
      `Command "${commandName}" does not have a callback function.`
    );
  }
};
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="no-callback.ts" %}

```typescript
import { Command } from "wokcommands";

export default (command: Command) => {
  const { commandObject, commandName } = command;

  if (!commandObject.callback) {
    throw new Error(
      `Command "${commandName}" does not have a callback function.`
    );
  }
};
```

{% endcode %}
{% endtab %}
{% endtabs %}


# Event Handling

{% embed url="<https://youtu.be/_67r4wq23BA?t=646>" %}

WOKCommands can automatically handle your event listening in multiple files and folders. You can even setup "dynamic validations" to only run some events when a specific condition is met. More on that in the next section of the documentation.

Here is an example of how to setup a basic event listening system:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="index.js" %}

```javascript
const { Client, IntentsBitField, Partials } = require("discord.js");
const path = require("path");
const WOK = require("wokcommands");
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  console.log("The bot is ready");

  new WOK({
    client,
    mongoUri: process.env.MONGO_URI || "",
    commandsDir: path.join(__dirname, "commands"),
    events: {
      // Where the events are stored
      dir: path.join(__dirname, "events"),
    },
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="index.ts" %}

```typescript
import { Client, IntentsBitField, Partials } from "discord.js";
import path from "path";
import WOK from "wokcommands";
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  console.log("The bot is ready");

  new WOK({
    client,
    mongoUri: process.env.MONGO_URI || "",
    commandsDir: path.join(__dirname, "commands"),
    events: {
      // Where the events are stored
      dir: path.join(__dirname, "events"),
    },
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}
{% endtabs %}

### File/Folder Structure

Inside of your "events" folder should be nested folders that **directly** match the event you want to listen to. An example of the "[messageCreate](https://discord.js.org/#/docs/discord.js/main/class/Client?scrollTo=e-messageCreate)" event:

![](https://848057878-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MY8r5FJ7sEk7fNghuKr%2Fuploads%2F2OjO6o1hJBSYNuBHDEHe%2Fimage.png?alt=media\&token=c288487e-4460-47f4-895d-0fa8bd04176b)

All files inside of the "messageCreate" folder will be ran when the event is emitted. The function inside of your event files should have all of the normal parameters for the event, plus an additional "WOKCommands" instance parameter at the end:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="log-messages.js" %}

```javascript
module.exports = (message, instance) => {
  console.log(message.content);
};
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="log-messages.ts" %}

```typescript
import { Message } from "discord.js";
import WOK from "wokcommands";

export default (message: Message, instance: WOK) => {
  console.log(message.content);
};
```

{% endcode %}
{% endtab %}
{% endtabs %}


# Dynamic Validations

{% embed url="<https://youtu.be/_67r4wq23BA?t=723>" %}

This is a system to only run specific event files when a specific condition is met. For example you might only want to listen for the "messageCreate" event whenever a human sent a message and not a bot. You can use dynamic validations to achieve this without adding complexity to your code.

Here is how you setup dynamic validations:

{% hint style="info" %}
The below dynamic validations are the default ones for WOKCommands. You do not need to implement these manually, but you can always add in your own.
{% endhint %}

{% tabs %}
{% tab title="JavaScript" %}
{% code title="index.js" %}

```javascript
const {
  Client,
  IntentsBitField,
  InteractionType,
  Partials,
} = require("discord.js");
const path = require("path");
const WOK = require("wokcommands");
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  console.log("The bot is ready");

  new WOK({
    client,
    mongoUri: process.env.MONGO_URI || "",
    commandsDir: path.join(__dirname, "commands"),
    events: {
      // Where the events are stored
      dir: path.join(__dirname, "events"),

      // Dynamic validations
      // IMPORTANT: These are the default dynamic validations that come with WOKCommands
      // no need to implement them manually

      // The name of the Discord.JS event
      interactionCreate: {
        // The name of your dynamic validation folder
        // This has no correlation to the Discord.JS event name
        // This will look for a direct parent folder called "isButton" and only
        // fire interactionCreate events in that folder if this method returns true.
        // In this case you should put button events in the "interactionCreate/isButton" folder
        isButton: (interaction) => interaction.isButton(),

        // In this case you should put slash command events in the "interactionCreate/isCommand" folder
        isCommand: (interaction) =>
          interaction.type === InteractionType.ApplicationCommand,

        // In this case you should put auto complete events in the "interactionCreate/isAutocomplete" folder
        isAutocomplete: (interaction) =>
          interaction.type === InteractionType.ApplicationCommandAutocomplete,
      },
      messageCreate: {
        isHuman: (message) => !message.author.bot,
      },
    },
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="index.ts" %}

```typescript
import {
  Client,
  IntentsBitField,
  Interaction,
  InteractionType,
  Message,
  Partials,
} from "discord.js";
import path from "path";
import WOK from "wokcommands";
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  console.log("The bot is ready");

  new WOK({
    client,
    mongoUri: process.env.MONGO_URI || "",
    commandsDir: path.join(__dirname, "commands"),
    events: {
      // Where the events are stored
      dir: path.join(__dirname, "events"),

      // Dynamic validations
      // IMPORTANT: These are the default dynamic validations that come with WOKCommands
      // no need to implement them manually

      // The name of the Discord.JS event
      interactionCreate: {
        // The name of your dynamic validation folder
        // This has no correlation to the Discord.JS event name
        // This will look for a direct parent folder called "isButton" and only
        // fire interactionCreate events in that folder if this method returns true.
        // In this case you should put button events in the "interactionCreate/isButton" folder
        isButton: (interaction: Interaction) => interaction.isButton(),

        // In this case you should put slash command events in the "interactionCreate/isCommand" folder
        isCommand: (interaction: Interaction) =>
          interaction.type === InteractionType.ApplicationCommand,

        // In this case you should put auto complete events in the "interactionCreate/isAutocomplete" folder
        isAutocomplete: (interaction: Interaction) =>
          interaction.type === InteractionType.ApplicationCommandAutocomplete,
      },
      messageCreate: {
        isHuman: (message: Message) => !message.author.bot,
      },
    },
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}
{% endtabs %}

As mentioned in the comments, you can specify a Discord.JS event name and a name for your dynamic validation. Your name can be anything, it doesn't have any correlation with Discord.JS method names at all.

The direct parent of your event files should match the dynamic validation name. In the example of a "log-messages" event file where we only want to log messages from humans and not bots:

![](https://848057878-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MY8r5FJ7sEk7fNghuKr%2Fuploads%2FnSzY9cKtZWQwNnj8eE9q%2Fimage.png?alt=media\&token=f29f7d81-bff9-43a2-a790-cbd19e1e53a9)

The "isHuman" dynamic validation must return true for the "log-messages" event handler to be ran. As you can see from our index file, the "isHuman" method returns true or false depending on if the message author is a bot or a human.


# Features

{% embed url="<https://youtu.be/_67r4wq23BA?t=788>" %}

Sometimes you want files to be ran without them being a command or a DJS event listener. WOKCommands refers to these files as "feature files". You can specify a "features" directory and all exported functions from files in that directory will be ran when your bot starts up.

Here is an example of how to specify your "features" folder:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="index.js" %}

```javascript
const { Client, IntentsBitField, Partials } = require("discord.js");
const path = require("path");
const WOK = require("wokcommands");
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  console.log("The bot is ready");

  new WOK({
    client,
    mongoUri: process.env.MONGO_URI || "",
    commandsDir: path.join(__dirname, "commands"),
    featuresDIr: path.join(__dirname, "features"),
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="index.ts" %}

```typescript
import { Client, IntentsBitField, Partials } from "discord.js";
import path from "path";
import WOK from "wokcommands";
require("dotenv/config");

const client = new Client({
  intents: [
    IntentsBitField.Flags.Guilds,
    IntentsBitField.Flags.GuildMessages,
    IntentsBitField.Flags.DirectMessages,
    IntentsBitField.Flags.MessageContent,
  ],
  partials: [Partials.Channel],
});

client.on("ready", () => {
  console.log("The bot is ready");

  new WOK({
    client,
    mongoUri: process.env.MONGO_URI || "",
    commandsDir: path.join(__dirname, "commands"),
    featuresDIr: path.join(__dirname, "features"),
  });
});

client.login(process.env.TOKEN);
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Example File

All functions that are exported from files in the "features" folder will now be ran whenever your bot starts up. The WOKCommands "instance" object and your bot's "client" object will be sent to this function. Example:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="feature-example.js" %}

```javascript
module.exports = (instance, client) => {
  console.log("Hello World!");
};
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="feature-example.ts" %}

```typescript
export default (instance: WOK, client: Client) => {
  console.log("Hello World!");
};
```

{% endcode %}
{% endtab %}
{% endtabs %}


# Enabling and disabling commands

WOKCommands comes with the ability for server owners using your bot to enable or disable commands within their server/guild. They can do this easily with the following command:

`/toggleCommand <Command name>`


# Configurable required roles

Server/guild owners can configure what roles are required to use specific commands:

`/requiredRole <Command name> <Role>`


# Configurable required permissions

Server/guild owners can configure what roles are required to use specific commands:

`/requiredPermissions <Command name> <Discord Permission>`


# Per-guild prefixes

Server/guild owners can configure what prefix your bot uses by using the following command:

`/prefix [new prefix]`

Omitting the prefix will display the current prefix for that server/guild. The default prefix for WOKCommands is a `!`


# Customizable channel specific commands

Server owners using your bot can set some commands to only be ran in specific channels within their server. They can do this with the following:

`/channelCommand <Command Name> [channel tag]`

If a user attempts to use a command in the wrong channel then they will be told what channels they are allowed to use.


# Custom commands

WOKCommands gives server owners the ability to add in simple custom commands. This is a basic command -> text reply command.

Here is how to create a custom command:

```
/customCommand create <Command Name> <Description> <Response>
```

Here is how to delete a custom command:

```
/customCommand delete <Command Name>
```


