npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ikucord

v1.1.11

Published

A discord.js command/event handler and more!

Downloads

1,134

Readme

IkuCord

IkuCord is a command and event framework, with extra features, for discord.js. It simplifies registration, handles command execution pipelines, provides middleware, and includes a cache backed cooldown / rate limiting system.

IkuCord only supports discord.js v14.

View the full documentation here

IkuCord is early in development. From testing with my own bot, it is stable for, at least, small scale bots. Please report any issues you encounter!! Things are to be improved, and more features are to be added!

Table of Contents

Features

  • Automatic Registration: Auto registers slash commands, autocomplete handlers, and User/Message Context Menus directly with Discord.
  • Command Aliases: Register multiple alternate names on Discord that map directly back to a single command handler.
  • Flexible Middleware Pipeline: Intercept commands with global, directory, and command level middlewares executing sequentially.
  • Cooldowns / Rate Limiting: Impose cache backed cooldowns / rate limits on commands and subcommands with developer and user bypasses.
  • Response Caching: Cache slash command responses per guild, channel, user, or globally. This caches the command's JSON sent to Discord with the data you fetched in the command handler. Please look into how this feature works to use it correctly
  • Extensible Handlers: Error handler to handle a generic response to any interaction that throws an error, and custom responses for when a command is on cooldown or not available. These handlers support embeds, components, and custom logic.

Installation

Ensure you have discord.js installed, then add ikucord:

npm add ikucord
bun add ikucord
pnpm add ikucord
yarn add ikucord

Quick Start

1. Initialize the Client

Initialize IkuCord in your entry file (e.g. index.ts). You can pass a token parameter in the options, or by default, IkuCord will use the env variable DISCORD_TOKEN.

import { IkuCord } from "ikucord";
import { IntentsBitField } from "discord.js";
import path from "node:path";

new IkuCord({
  directories: {
    commands: path.join(__dirname, "commands"),
    events: path.join(__dirname, "events")
  },
  clientOptions: {
    intents: [
      IntentsBitField.Flags.Guilds,
      IntentsBitField.Flags.GuildMessages,
      IntentsBitField.Flags.MessageContent
    ]
  }
});

Awaiting Initialization

If you need to access the client outside of command handlers (such as at setup or module load time) and want to guarantee that IkuCord has fully loaded, you can safely await IkuCord.waitUntilReady(). This can be called from anywhere, even before new IkuCord() is constructed:

import { IkuCord } from "ikucord";

// Call this in an async context or function
async function run() {
  await IkuCord.waitUntilReady();
  const client = IkuCord.getClient();
  // client is now initialized and ready to use
}

2. Create a Command

Create command files within your commands directory (organized into subfolders representing command directories/categories). IkuCord also supports optional aliases, which register multiple slash commands under different names but execute the same handler.

import type { IkuCommand } from "ikucord";

const pingCommand: IkuCommand = {
  settings: {
    name: "ping",
    description: "Replies with pong!",
    aliases: ["p", "latency"], // Optional: registers /p and /latency mapping to this command
    cooldown: {
      time: "3s"
    }
  },
  handler: async ({ interaction }) => {
    await interaction.reply("Pong!");
  }
};

export default pingCommand;

Event Handling

Events are automatically registered from your events directory (configured via directories.events). The framework looks for an index.ts file within that folder.

This index file must default export (or export a named events object) conforming to IkuCordEventsRegistry.

Multi Handler Execution Order

Each event option accepts an array of handler functions. The framework executes these event handlers sequentially, in the exact order they are declared in the array. If one handler fails, it logs the error but does not prevent subsequent handlers in the array from running.

Using Explicit EventHandler Types

Instead of defining functions inline, you can explicitly type your functions using the generic EventHandler<K> type (where K is the discord.js event name). This provides full type safety for event parameters.

Here is an example structure defining multiple handlers for messageCreate and clientReady:

import { type IkuCordEventsRegistry, type EventHandler, Log } from "ikucord";

// Define individual event handlers using the EventHandler type
const logOnReady: EventHandler<"clientReady"> = async (client) => {
  Log.event("clientReady", `Logged in as ${client.user?.tag}!`);
};

const setBotActivity: EventHandler<"clientReady"> = async (client) => {
  client.user?.setActivity("Managing Discord servers");
};

const ignoreBots: EventHandler<"messageCreate"> = async (message, client) => {
  if (message.author.bot) return;
  Log.info(`User sent message: ${message.content}`);
};

const commandLogger: EventHandler<"messageCreate"> = async (message, client) => {
  if (message.content.startsWith("!")) {
    Log.info(`Command prefix matched in message: ${message.content}`);
  }
};

const localEventsRegistry: IkuCordEventsRegistry = {
  clientReady: {
    enabled: true,
    // Runs 'logOnReady' first, followed by 'setBotActivity'
    functions: [logOnReady, setBotActivity]
  },
  messageCreate: {
    enabled: true,
    // Runs 'ignoreBots' first, followed by 'commandLogger'
    functions: [ignoreBots, commandLogger]
  }
};

export default localEventsRegistry;

Middleware Configuration

IkuCord features a middleware execution pipeline that runs before and after your command handlers. Middlewares are divided into three levels, executed in order: Global ➔ Directory ➔ Command.

Middleware Structure

A middleware implements the IkuCommandMiddleware interface:

import type { ChatInputCommandInteraction, Client } from "discord.js";
import type { IkuCommand } from "ikucord";

export interface IkuCommandMiddleware {
  beforeRun?: (interaction: ChatInputCommandInteraction, client: Client, command?: IkuCommand) => void | Promise<void>;
  afterRun?: (interaction: ChatInputCommandInteraction, client: Client, command?: IkuCommand, error?: Error | null) => void | Promise<void>;
}
  • beforeRun: Executes before permission checks, cooldown checks, and the command handler. Receives the interaction, the discord.js client, and command (your IkuCommand object).
  • afterRun: Executes in a finally block after the command handler completes (regardless of whether it succeeded or threw an error). Receives the same parameters, plus an error parameter representing any error thrown during command execution (or null if the command completed successfully).

1. Global Middleware

Global middlewares run on every single command.

  • Filename: $global.middleware.ts.
  • Location: Must be placed in the parent directory of your commands folder (the parent of settings.directories.commands).
// $global.middleware.ts
import type { IkuCommandMiddleware } from "ikucord";

const globalMiddleware: IkuCommandMiddleware = {
  beforeRun: async (interaction, client, command) => {
    console.log(`Global check: User ${interaction.user.tag} is running /${interaction.commandName}`);
  },
  afterRun: async (interaction, client, command) => {
    console.log(`Global check: /${interaction.commandName} execution finished`);
  }
};

export default globalMiddleware;

2. Directory Middleware

Directory middlewares run on all commands inside a specific subdirectory of your commands folder.

  • Filename: $dir.middleware.ts.
  • Location: Must be placed inside the command subdirectory (e.g. commands/admin/$dir.middleware.ts).
// commands/admin/$dir.middleware.ts
import type { IkuCommandMiddleware } from "ikucord";

const adminDirectoryMiddleware: IkuCommandMiddleware = {
  beforeRun: async (interaction, client, command) => {
    console.log(`Running admin command check for /${interaction.commandName}`);
  }
};

export default adminDirectoryMiddleware;

3. Command Middleware

Command middlewares run only on the specific command where they are defined.

  • Location: Defined directly within the command file as a property of the exported IkuCommand.
// commands/general/ping.ts
import type { IkuCommand } from "ikucord";

const pingCommand: IkuCommand = {
  settings: {
    name: "ping",
    description: "Ping pong!"
  },
  middleware: {
    beforeRun: async (interaction, client, command) => {
      console.log("Ping middleware running");
    }
  },
  handler: async ({ interaction }) => {
    await interaction.reply("Pong!");
  }
};

export default pingCommand;

Halting Command Execution

You can halt command execution inside beforeRun by calling IkuCordMiddleware.before.stop(message?: string, skipAfterMiddleware?: boolean). This throws an IkuCordMiddlewareError with the message you specified, or a default one if you didn't. This stops the middleware pipeline and the command from running. Make sure to reply to the interaction yourself before calling stop() if you want the user to receive a response.

import { IkuCordMiddleware } from "ikucord";
import type { IkuCommandMiddleware } from "ikucord";
import { MessageFlags } from "discord.js"

const maintenanceMiddleware: IkuCommandMiddleware = {
  beforeRun: async (interaction, client, command) => {
    const isMaintenance = true;
    
    if (isMaintenance) {
      // Reply to the interaction manually before halting
      await interaction.reply({
        content: "The bot is currently undergoing maintenance. Please try again later.",
        flags: MessageFlags.Ephemeral
      });
 
      // Halts execution. Set the second argument to true to skip executing afterRun middlewares
      IkuCordMiddleware.before.stop("maintenance", true);
    }
  }
};

export default maintenanceMiddleware;

Command Options, Autocomplete & Subcommands

IkuCord fully supports standard Discord slash command options, dynamic autocompletes, subcommands, and subcommand groups using TypeScript safe definitions.

1. Adding Options and Autocomplete

To use options, define the options array in settings. For dynamic user input suggestions, set autocomplete: true and provide an autocomplete function handler in your command object:

import { ApplicationCommandOptionType } from "discord.js";
import type { IkuCommand } from "ikucord";

const searchCommand: IkuCommand = {
  settings: {
    name: "search",
    description: "Search for items",
    options: [
      {
        name: "query",
        description: "The term to search for",
        type: ApplicationCommandOptionType.String,
        autocomplete: true,
        required: true
      },
      {
        name: "category",
        description: "Filter search by category",
        type: ApplicationCommandOptionType.String,
        choices: [
          { name: "Books", value: "books" },
          { name: "Movies", value: "movies" }
        ],
        required: false
      }
    ]
  },
  autocomplete: async ({ interaction, client, focusedOption }) => {
    // focusedOption contains the option currently typed by the user
    const choices = ["perfect blue", "lord of the rings", "interstellar", "inception"];
    const filtered = choices.filter(choice => choice.startsWith(String(focusedOption.value).toLowerCase()));
    
    // Return up to 25 choice objects { name: string, value: string | number }
    return filtered.map(choice => ({ name: choice, value: choice }));
  },
  handler: async ({ interaction }) => {
    const query = interaction.options.getString("query");
    const category = interaction.options.getString("category") ?? "all";
    await interaction.reply(`Searching for "${query}" in category "${category}"...`);
  }
};

export default searchCommand;

2. Subcommands and Subcommand Groups

Organize your commands using nested subcommands or subcommand groups by setting the option's type to ApplicationCommandOptionType.Subcommand or SubcommandGroup:

import { ApplicationCommandOptionType } from "discord.js";
import type { IkuCommand } from "ikucord";

const configCommand: IkuCommand = {
  settings: {
    name: "config",
    description: "Configure bot settings",
    options: [
      {
        name: "set",
        description: "Set a configuration value",
        type: ApplicationCommandOptionType.Subcommand,
        options: [
          {
            name: "key",
            description: "The setting key to modify",
            type: ApplicationCommandOptionType.String,
            required: true
          },
          {
            name: "value",
            description: "The new value for the key",
            type: ApplicationCommandOptionType.String,
            required: true
          }
        ]
      },
      {
        name: "view",
        description: "View current configuration settings",
        type: ApplicationCommandOptionType.Subcommand
      }
    ]
  },
  handler: async ({ interaction }) => {
    const subcommand = interaction.options.getSubcommand();

    if (subcommand === "set") {
      const key = interaction.options.getString("key");
      const value = interaction.options.getString("value");
      await interaction.reply(`Setting \`${key}\` has been set to \`${value}\`.`);
    } else if (subcommand === "view") {
      await interaction.reply("Current configuration: Key=Value");
    }
  }
};

export default configCommand;

Context Menu Commands

IkuCord supports Discord's User and Message Context Menus. These commands appear when right clicking a user or a message in the Discord UI.

Registration and Structure

Context menu files must be placed within your commands directory structure.

To define a context menu command, export a default object of type IkuContextMenuCommand:

1. User Context Menus

import { MessageFlags } from "discord.js";
import type { IkuContextMenuCommand } from "ikucord";

const userInfoContextMenu: IkuContextMenuCommand = {
  settings: {
    name: "User Info",
    type: "user", // Tells Discord to display this context menu on Users
    enabled: true, // Optional (defaults to true)
    devOnly: false, // Optional: restricts context menu to dev IDs
    testOnly: false // Optional: registers context menu to the devGuildID only
  },
  handler: async ({ interaction }) => {
    if (!interaction.isUserContextMenuCommand()) return;
    
    const targetUser = interaction.targetUser;
    await interaction.reply({
      content: `Username: ${targetUser.username}\nID: \`${targetUser.id}\``,
      flags: MessageFlags.Ephemeral
    });
  }
};

export default userInfoContextMenu;

2. Message Context Menus

import { MessageFlags } from "discord.js";
import type { IkuContextMenuCommand } from "ikucord";

const messageIdContextMenu: IkuContextMenuCommand = {
  settings: {
    name: "message-id",
    type: "message", // Tells Discord to display this context menu on Messages
    enabled: true
  },
  handler: async ({ interaction }) => {
    if (!interaction.isMessageContextMenuCommand()) return;
    
    const targetMessage = interaction.targetMessage;
    await interaction.reply({
      content: `Message ID: \`${targetMessage.id}\``,
      flags: MessageFlags.Ephemeral
    });
  }
};

export default messageIdContextMenu;

Cooldown Configuration

Cooldowns are backed by the internal caching layer. You configure the cooldown object directly inside the command's settings block. You can specify durations using readable strings (e.g. 10s, 15m, 1hr, 2d).

Supported Duration Formats

Both cooldowns and cache lifetimes accept duration strings. You can also combine multiple units (e.g., 1h 30m).

| Unit | Supported Abbreviations / Suffixes | Example | | :--- | :--- | :--- | | Milliseconds | ms | 500ms | | Seconds | s, sec, secs, second, seconds | 30s | | Minutes | m, min, mins, minute, minutes | 5m | | Hours | h, hr, hrs, hour, hours | 2h | | Days | d, day, days | 1d | | Weeks | w, wk, wks, week, weeks | 1w | | Months | mo, mon, mth, mths, month, months (30 days) | 1mo | | Years | y, yr, yrs, year, years (365 days) | 1y |

const exampleCommand: IkuCommand = {
  settings: {
    name: "example",
    description: "Example command with rate limiting",
    cooldown: {
      time: "5m",
      amount: 5, // Allow up to 5 execution casts before triggering cooldown (defaults to 1)
      devBypass: true, // Developers bypass cooldowns (defaults to true)
      bypassUsers: ["USER_ID_1", "USER_ID_2"] // Specific users who bypass this cooldown
    }
  },
  handler: async ({ interaction }) => {
    await interaction.reply("Command executed!");
  }
};

Subcommand Cooldowns

You can configure cooldowns on individual subcommands inside the command's options array. If a subcommand has a cooldown block, it tracks execution limits independently using an isolated cache key unique to that subcommand. If a subcommand does not have its own cooldown configuration, it automatically falls back to the parent command's top level cooldown.

import { ApplicationCommandOptionType } from "discord.js";
import type { IkuCommand } from "ikucord";

const configCommand: IkuCommand = {
  settings: {
    name: "config",
    description: "Configure bot settings",
    cooldown: {
      time: "10s" // Fallback cooldown for subcommands without specific rate limits
    },
    options: [
      {
        name: "set",
        description: "Set a configuration value",
        type: ApplicationCommandOptionType.Subcommand,
        cooldown: {
          time: "3s" // Independent cooldown specifically for this subcommand
        },
        options: [
          {
            name: "key",
            description: "The setting key to modify",
            type: ApplicationCommandOptionType.String,
            required: true
          }
        ]
      },
      {
        name: "view",
        description: "View settings",
        type: ApplicationCommandOptionType.Subcommand
        // Falls back to the parent command's 10s cooldown
      }
    ]
  },
  handler: async ({ interaction }) => {
    
  }
};

Command Response Caching

You can optionally cache the responses of your slash commands using the internal/configured caching layer. This avoids running your command handler multiple times for identical inputs, saving API requests, server load, and database queries.

To enable caching, define the cache object within the command's settings:

import { ApplicationCommandOptionType } from "discord.js";
import type { IkuCommand } from "ikucord";

const weatherCommand: IkuCommand = {
  settings: {
    name: "weather",
    description: "Get the current weather",
    cache: {
      time: "5m", // Cache duration (supports readable strings like '10s', '15m', '1hr')
      scope: "guild" // Optional scope: 'global' | 'guild' | 'channel' | 'user' (defaults to 'global')
    },
    options: [
      {
        name: "location",
        description: "The city to search for",
        type: ApplicationCommandOptionType.String,
        required: true
      }
    ]
  },
  handler: async ({ interaction }) => {
    const location = interaction.options.getString("location");
    // This database/API fetch will only run once per 5 minutes per guild!
    const weather = await fetchWeatherFromAPI(location);
    await interaction.reply(`The weather in ${location} is ${weather}.`);
  }
};

How it Works

  1. Option Sensitive Keys: The framework automatically serializes all command arguments (options) passed by the user, sorting them alphabetically to produce a deterministic cache key unique to the inputs.
  2. Isolation Scopes:
    • global: Cache is shared bot wide (all guilds, channels, and users see the cached result for identical options).
    • guild: Cache is isolated to the Discord server where the command was run.
    • channel: Cache is isolated to the specific text channel.
    • user: Cache is isolated to the individual executing user.
  3. Execution Interception: If a cached response exists, the framework intercepts the command and replays the cached message instantly, bypassing execution of your handler completely.

Subcommand Caching

You can configure cache rules on individual subcommands inside the command's options array. If a subcommand has its own cache block, caching is isolated to that subcommand's executions. If a subcommand does not define its own caching configuration, it falls back to the parent command's top level cache settings (if set).

import { ApplicationCommandOptionType } from "discord.js";
import type { IkuCommand } from "ikucord";

const configCommand: IkuCommand = {
  settings: {
    name: "data",
    description: "Fetch cached data",
    cache: {
      time: "10m" // Fallback cache settings for subcommands
    },
    options: [
      {
        name: "get",
        description: "Get data by ID",
        type: ApplicationCommandOptionType.Subcommand,
        cache: {
          time: "1m", // Subcommand level override
          scope: "user"
        },
        options: [
          {
            name: "id",
            description: "The data ID",
            type: ApplicationCommandOptionType.String,
            required: true
          }
        ]
      },
      {
        name: "list",
        description: "List all items",
        type: ApplicationCommandOptionType.Subcommand
        // Falls back to the parent command's 10 minute global cache
      }
    ]
  },
  handler: async ({ interaction }) => {

  }
};

Preventing Caching on Handled Errors

By default, any interaction reply, editReply, or follow up captured during a command handler execution will be cached for the configured duration. If your command catches an error internally and replies with a handled error embed/message, that response would normally be cached.

To prevent handled errors or specific executions from being cached, call IkuCordCache.cancelCommandCache() at any point inside your command handler:

import { IkuCordCache, type IkuCommand } from "ikucord";
import { MessageFlags } from "discord.js";

const myCommand: IkuCommand = {
  // ... settings with cache config
  handler: async ({ interaction }) => {
    try {
      const result = await performAction();
      await interaction.reply(result);
    } catch (error) {
      // Prevent the error response from being cached
      IkuCordCache.cancelCommandCache();
      
      await interaction.reply({
        content: "Failed to perform action.",
        flags: MessageFlags.Ephemeral
      });
    }
  }
};

Using Cache and Time Utilities

The framework exposes direct utilities for caching and time parsing/formatting.

Caching Utility

Import IkuCordCache to read, write, or delete values directly from the configured cache store (whether utilizing the default in memory store or a custom Redis/etc. backing). It supports automatic JSON serialization and deserialization for structured objects:

import { IkuCordCache } from "ikucord";

interface UserProfile {
  username: string;
  points: number;
}

// 1. Write an object directly (automatically serialized to JSON under the hood)
await IkuCordCache.set("user:123", { username: "ikuyaa", points: 150 }, 60000);

// 2. Read with a generic type parameter to retrieve a parsed, type safe object
const user = await IkuCordCache.get<UserProfile>("user:123");
console.log(user?.username); // "ikuyaa"

// 3. Read strings as raw values (generic defaults to string)
await IkuCordCache.set("my-custom-key", "my-value", 60000);
const data = await IkuCordCache.get("my-custom-key"); // Resolves to type: string | null

// 4. Delete from cache
await IkuCordCache.delete("my-custom-key");

Time Utilities

Import TimeMS (milliseconds) or TimeSecs (seconds) to perform time conversions, parse readable durations, or format durations:

import { TimeMS, TimeSecs } from "ikucord";

// Conversion helpers
TimeMS.secs(5);      // => 5000 (ms)
TimeMS.mins(2);      // => 120000 (ms)
TimeSecs.mins(5);    // => 300 (seconds)

// Parse readable duration string into milliseconds
const duration = TimeMS.parse("1h 30m"); // => 5400000

// Format milliseconds into a readable string
const formatted = TimeMS.format(90000); // => "1 minute 30 seconds"

Lifecycle Overrides

Configure custom responses for cooldowns or execute custom handlers for errors globally in settings:

  • cooldownHandler: IkuCord will automatically reply when a user tries to use a command that is on a cooldown, but you may want to send a different reply, or run logic before sending the reply. You can do this by providing a cooldownHandler.
  • errorHandler: This is where you can send a generic reply to any command that errors.
import { Colors, EmbedBuilder, MessageFlags } from "discord.js";

new IkuCord({
  // ...other options
  cooldownHandler: async (interaction, timeLeft, command) => {
    const embed = new EmbedBuilder()
      .setTitle("Command Cooldown")
      .setDescription(`Please wait **${timeLeft.toFixed(1)}s** before running \`/${command.settings.name}\` again.`)
      .setColor(Colors.Blue);

    await interaction.reply({
      embeds: [embed],
      flags: MessageFlags.Ephemeral
    });
  },
  errorHandler: async (interaction, error, command) => {
    const replyOptions = {
      content: `Something went wrong running \`/${command?.settings.name}\`: ${error.message}`,
      flags: MessageFlags.Ephemeral
    };

    if (!interaction.replied && !interaction.deferred) {
      await interaction.reply(replyOptions);
    } else if (interaction.deferred && !interaction.replied) {
      await interaction.editReply(replyOptions);
    } else {
      await interaction.followUp(replyOptions);
    }
  }
});

Custom Cache Backing

By default, IkuCord uses an in memory cache for tracking cooldowns, caching commands, etc. If you run multiple bot shards or need persistent cooldown states across restarts, you can override the backing cache store in settings using any custom provider like Redis:

import { IkuCord } from "ikucord";
import Redis from "ioredis";

const redis = new Redis("redis://localhost:6379");

new IkuCord({
  // ...other options
  cache: {
    get: async (key) => {
      return await redis.get(key);
    },
    set: async (key, value, ttl) => {
      if (ttl) {
        // ttl is provided in milliseconds. You'd want to convert the TTL to seconds for redis.
        await redis.set(key, value, "PX", ttl / 1000);
      } else {
        await redis.set(key, value);
      }
    },
    delete: async (key) => {
      await redis.del(key);
    }
  }
});

Configuration Reference

Framework Settings

Pass these options inside the new IkuCord(settings) constructor:

| Option | Type | Description | | :--- | :--- | :--- | | token | string | Optional. The Discord bot token. Defaults to process.env.DISCORD_TOKEN. | | clientOptions | ClientOptions | Required. Standard discord.js client constructor options (e.g. intents). | | directories | object | Required. Paths for loading resources:commands (string): Absolute path to the commands folder.events (string): Absolute path to the events folder (containing index.ts). | | devUserIDs | string[] | Optional. List of Discord user IDs treated as developers. Used for developer checks and cooldown bypasses. | | devGuildID | string | Optional. The guild ID used to register dev only or test only commands instantly. | | deleteUnregisteredCommands | boolean | Optional. Automatically delete application commands registered on Discord that are not found or enabled in the application. Defaults to true. | | cooldownHandler | function | Optional. Callback executed when a command is on cooldown. | | errorHandler | function | Optional. Callback executed when a command execution throws an error. | | cache | object | Optional. Custom cache backing implementation (implements get, set, delete). | | logger | object | Optional. Configuration settings for the framework log emitter. See Logger Settings below. |

Logger Settings

Configure log output options inside the logger object:

| Option | Type | Description | | :--- | :--- | :--- | | enabled | boolean | Toggle overall logger activity (defaults to true). | | level | string | Standard log level threshold (e.g. "info", "debug", "error"). | | timeFormat | "12HR" \| "24HR" | Timestamp representation format (defaults to "24HR"). | | middlewareLog | boolean | Enable/disable middleware execution events output. | | commandLog | boolean | Enable/disable command registration and execution events output. | | eventLog | boolean | Enable/disable listener lifecycle events output. | | fileLogging | object | Optional. Automatically write logs to local files:enabled (boolean): Toggle text file output.logFolder (string): Output directory for saved log files.logRetentionDays (number): Lifespan threshold for automated log cleanup. |

Command Settings

Define these settings inside each IkuCommand structure:

| Option | Type | Description | | :--- | :--- | :--- | | name | string | Required. Unique identifier and registration name for the slash command (lowercase). | | description | string | Required. Short explanation of what the command does. | | aliases | string[] | Optional. Additional command names registered on Discord that map to this command. | | enabled | boolean | Optional. Toggle whether the command should be loaded and registered (defaults to true). | | devOnly | boolean | Optional. Restrict execution to developer IDs declared in settings. | | testOnly | boolean | Optional. Restrict command registration to the designated devGuildID. | | permissionsRequired | PermissionResolvable[] | Optional. Array of discord.js permissions the executing user must possess. | | botPermissionsRequired | PermissionResolvable[] | Optional. Array of discord.js permissions the bot client must possess. | | cooldown | object | Optional. Cooldown/rate limiting rules:time (string): Duration threshold (e.g. "10s", "15m", "1hr").amount (number): Allowable execution casts before triggering cooldown (defaults to 1).devBypass (boolean): Developers bypass cooldowns (defaults to true).bypassUsers (string[]): Specific Discord user IDs exempt from this cooldown. | | cache | object | Optional. Response caching rules:time (string): Cache duration threshold (e.g. "5m", "1hr").scope (string): Cache isolation scope ("global" \| "guild" \| "channel" \| "user", defaults to "global"). | | additionalFields | Record<string, any> | Optional. Custom metadata fields that you can query in custom middlewares or error handlers. |

Context Menu Settings

Define these settings inside each IkuContextMenuCommand structure:

| Option | Type | Description | | :--- | :--- | :--- | | name | string | Required. Name of the context menu option as it appears in the Discord UI. | | type | "user" \| "message" | Required. Target type of the context menu. | | enabled | boolean | Optional. Toggle whether the context menu command should be loaded and registered (defaults to true). | | devOnly | boolean | Optional. Restrict execution to developer IDs declared in settings. | | testOnly | boolean | Optional. Restrict context menu registration to the designated devGuildID. |