{"id":21578873,"url":"https://github.com/yetnt/ic4d","last_synced_at":"2026-02-12T00:02:30.129Z","repository":{"id":200211044,"uuid":"704842774","full_name":"yetnt/ic4d","owner":"yetnt","description":"Interaction and Command handler 4 Dummies","archived":false,"fork":false,"pushed_at":"2025-03-02T11:32:19.000Z","size":201,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-05T07:20:36.279Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yetnt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-10-14T09:05:05.000Z","updated_at":"2025-03-02T11:31:48.000Z","dependencies_parsed_at":"2023-11-10T16:27:04.509Z","dependency_job_id":"bf3c2a30-f3dc-4d35-b1d7-1dab63237e25","html_url":"https://github.com/yetnt/ic4d","commit_stats":null,"previous_names":["yetnt/ic4d","yetnt/int4d"],"tags_count":61,"template":false,"template_full_name":null,"purl":"pkg:github/yetnt/ic4d","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yetnt%2Fic4d","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yetnt%2Fic4d/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yetnt%2Fic4d/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yetnt%2Fic4d/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yetnt","download_url":"https://codeload.github.com/yetnt/ic4d/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yetnt%2Fic4d/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29350082,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-11T20:11:40.865Z","status":"ssl_error","status_checked_at":"2026-02-11T20:10:41.637Z","response_time":97,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-24T13:11:47.184Z","updated_at":"2026-02-12T00:02:30.123Z","avatar_url":"https://github.com/yetnt.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ic4d\n\n**I**nteractions and **C**ommand handler **4** **D**ummies\n\n# Installation\n\nWith npm\n\n```\nnpm i ic4d\n```\n\nwith yarn\n\n```\nyarn add ic4d\n```\n\n```js\nconst ic4d = require(\"ic4d\");\n// or\nconst {\n    /* Classess you need seprated by a comma */\n} = require(\"ic4d\");\n```\n\nand for yall ts lovers (I tried using this in ts and damn is it hard work.)\n\n```ts\nimport * as ic4d from \"ic4d\";\n// or\nimport /* Classes and/or Interfaces you need separated by a comma */ \"ic4d\";\n```\n\n# Contents\n\nIf any method/function has no return documentation, it returns void.\n\n-   [ic4d](#ic4d)\n-   [Installation](#installation)\n-   [Contents](#contents) _You are here_\n-   [Quick Example](#quick-example)\n-   Classes\n    -   [CoreHandler](#corehandler)\n    -   [ReadyHandler](#readyhandler)\n    -   [CommandHandler](#commandhandler)\n    -   [InteractionHandler](#interactionhandler)\n    -   [SlashCommandManager](#slashcommandmanager)\n    -   [InteractionBuilder](#interactionbuilder)\n    -   [ContextMenuBuilder](#contextmenubuilder)\n\nFor TS Lovers:\n\n-   Interfaces\n    -   [RunFlags](#runflags)\n    -   [HandlerFlags](#handlerflags)\n    -   [InteractionHandlerFlags](#interactionhandlerflags)\n    -   [LoaderOptions](#loaderoptions)\n-   Other Types\n    -   [InteractionTypeStrings](#interactiontypestrings)\n-   [Common Problems](#common-problems)\n-   [Credit](#credits)\n-   [Links](#links)\n\n# Quick Example\n\n[Here's the example bot](https://github.com/YetNT/ic4d-example-bot) if you don't like reading\n\nthis is what you're index.js should look something like.\n\nRefer [here](#sharding) for the sharding version of index.js\n\n```js\nrequire(\"dotenv\").config();\nconst { Client, IntentsBitField } = require(\"discord.js\");\nconst path = require(\"path\");\n\nconst { CommandHandler, ReadyHandler, CoreHandler } = require(\"ic4d\");\n\nconst commandsPath = path.join(__dirname, \"..\", \"commands\");\nconst logpath = path.join(__dirname, \"..\", \"logs\");\n\nconst runFlags = {\n    devs: [\"671549251024584725\"],\n    testGuildId: \"808701451399725116\",\n};\n\nconst client = new Client({\n    intents: [\n        IntentsBitField.Flags.Guilds,\n        IntentsBitField.Flags.GuildMessages,\n    ],\n});\n\nconst core = new CoreHandler(client, logPath);\n\nconst handler = new CommandHandler(core, commandsPath, runFlags);\nconst ready = new ReadyHandler(\n    core,\n    async (client) =\u003e {\n        console.log(`${client.user.tag} is ready!`);\n    },\n    async () =\u003e {\n        await handler.registerCommands();\n    }\n);\n\n(async () =\u003e {\n    ready.execute();\n    await handler.handleCommands();\n})();\n\nclient.login(process.env.TOKEN);\n```\n\nAnd in any file in any folder under your specified `commands` directory\n\n```js\nconst { EmbedBuilder, SlashCommandBuilder } = require(\"discord.js\");\nconst { SlashCommandObject, SlashCommandManager } = require(\"ic4d\");\n\nconst ping = new SlashCommandManager({\n    data: new SlashCommandBuilder().setName(\"ping\").setDescription(\"Pong!\"),\n    async execute(interaction, client) {\n        try {\n            const sent = await interaction.reply({\n                embeds: [new EmbedBuilder().setDescription(\"Pinging...\")],\n                fetchReply: true,\n            });\n            interaction.editReply({\n                embeds: [\n                    new EmbedBuilder()\n                        .setTitle(\"Pong!\")\n                        .setFields([\n                            {\n                                name: \"Roundtrip latency\",\n                                value: `${\n                                    sent.createdTimestamp -\n                                    interaction.createdTimestamp\n                                }ms`,\n                                inline: true,\n                            },\n                            {\n                                name: \"Websocket heartbeat\",\n                                value: `${client.ws.ping}ms.`,\n                                inline: true,\n                            },\n                        ])\n                        .setColor(\"Green\"),\n                ],\n            });\n        } catch (error) {\n            console.error(error);\n        }\n    },\n});\n\nping.category = \"misc\"; // if you want to add your own property to the exorted object, you can do this\n\nmodule.exports = ping;\n// or\nmodule.exports = { ping };\n```\n\n# CoreHandler\n\nThis is a class which is needed as the first parameter of the `ReadyHandler`, `CommandHandler` and `InteractionHandler` constructors.\n\nYou don't need to use or touch any of the methods and properties in this class. Do that and your bot may not work lol\n\n## Constructor\n\n-   `client`**: [Client](https://discord.js.org/docs/packages/discord.js/main/Client:Class)**\n    -   **(optional)** Discord.js Client Instance.\n-   `logToFolder`**: string | false**\n    -   **(optional)** Default folder to log to.\n\n```js\nconst { CoreHandler } = require(\"ic4d\");\nconst { Client } = require(\"discord.js\");\n\nconst client = new Client();\n\nconst core = new CoreHandler(client, \"./logs\");\n```\n\n# ReadyHandler\n\nReady handler is a handler that runs a set of functions when the bot starts.\n\n## Constructor\n\n-   `core`**:[CoreHandler](#corehandler)**\n    -   CoreHandler instance.\n-   `...functions`**: ((client?: [Client](https://discord.js.org/docs/packages/discord.js/main/Client:Class)) =\u003e Promise\\\u003cvoid\u003e | void )[] = []**\n    -   Functions to run when the `execute()` method is called, and the ready event has been emitted. Functions may take one parameter (client) or none.\n\n```js\nconst { ReadyHandler, CoreHandler } = require(\"ic4d\");\n\nconst core = new CoreHandler(client, \"./logs\");\n\nconst ready = new ReadyHandler(\n    core\n    (client) =\u003e {\n        console.log(`${client.user.tag} is ready!`);\n    },\n    () =\u003e {\n        console.log(\"Lol another function\");\n    }\n);\n```\n\n## Methods\n\n### `execute()`\n\nStart listening for the bot's ready event and execute functions once the event is called.\n\n```js\nconst ready = new ReadyHandler(client, ...)\n\nready.execute()\n```\n\n# CommandHandler\n\nCommand Handler, which handles slash command creation, deletion, editing and running of slash commands\n\n## Constructor\n\n### Parameters\n\n-   `core`**:[CoreHandler](#corehandler)**\n    -   CoreHandler instance.\n-   `path`**: string**\n    -   Path in which your exported command objects are stored. The handler will **not** work if you do not use path.\n-   `runFlags`**: [RunFlags](#runflags)**\n    -   **(optional)** Command Reader Options\n-   `loaderOptions`**: [LoaderOptions](#loaderoptions)**\n    -   **(optional)** Command Loader Options\n-   `handlerFlags`**: [HandlerFlags](#handlerflags)**\n    -   **(optional)** Injection Options. (flags to set which do something while commandHandler is running)\n\n```js\nconst { CommandHandler, CoreHandler } = require(\"ic4d\");\nconst path = require(\"path\");\n\nconst core = new CoreHandler(client, \"./logs\");\n\nconst handler = new CommandHandler(core, path.join(__dirname, \"commands\"));\n```\n\n## Methods\n\n### `registerCommands()`\n\n**(asynchronous function)**\n\n-   `logNoChanges`**: boolean**\n    -   **(optional)** Log when loading a command and no changes are made\n-   `serverId`**: string**\n    -   **(optional)** Register all commands in a specific server. if not provided it will be application wide\n\n```js\nconst handler = new CommandHandler(client, path.join(__dirname, \"commands\"));\n\nasync () =\u003e {\n    await handler.registerCommands();\n};\n```\n\n### `handleCommands()`\n\n**(asynchronous function)**\n\n-   `middleWare`**: ( ( commandObject: Object, interaction?: [ChatInputCommandInteraction](https://discord.js.org/docs/packages/discord.js/main/ChatInputCommandInteraction:Class) ) =\u003e number | Promise\u003cnumber\u003e )[]**\n    -   Functions to run BEFORE a command is run.\n-   `postWare`**: ( ( commandObject: Object, interaction?: [ChatInputCommandInteraction](https://discord.js.org/docs/packages/discord.js/main/ChatInputCommandInteraction:Class) ) =\u003e any )[]**\n    -   Functions to run AFTER the command's callback has been called.\n\n```js\nconst handler = new CommandHandler(core, path.join(__dirname, \"commands\"));\n\nconst blacklisted = [\"302983482377931\"];\nconst blacklist = (commandObject, interaction) =\u003e {\n    if (commandObject.blacklist \u0026\u0026 blacklisted.includes(interaction.user.id)) {\n        interaction.reply({\n            content: \"Daang you blacklisted my guy.\",\n            ephemeral: true,\n        });\n        return 1;\n    }\n    return 0;\n};\n\nconst addXp = (commandObject, interaction) =\u003e {\n    if (commandObject.category != \"economy\") return;\n\n    interaction.reply({\n        content: \"Ayo! Free Xp +2\",\n        ephemeral: true,\n    });\n};\n\nawait handler.handleCommands([blacklist], [addXp]);\n```\n\n#### Middleware Parameters and use\n\n\u003e [!NOTE]  \n\u003e This is ONLY for `middleWare` and does NOT apply to `postWare` functions.\n\u003e It does not matter what `postWare` functions return as ic4d does not use that value at all.\n\nMiddleware is to define your own custom functions you want to run when a command is run by anyone. This can be a function to check for cooldown or function to add XP to a user.\n\nMiddleware that the package already contains is :\n\n-   Check to see if developer command\n-   Check to see if bot has sufficient permissions\n-   Check to see if user has sufficient permissions\n\nThe Middleware **must** take in these parameters\n\n-   `commandObject`: This is the commandObject that every command contains, this can check for the commands name, description, options, choices or a custom property you wish\n-   `interaction`**(optional)**: If the middleware function requires you to take in interaction for some reason, here you go 😃\n\nAnd should always return 1 or another number. If it returns 1 it counts as a fail so the function won't proceed. Another number returned is okay seen as a pass and the function continues.\n(If you don't understand, if a normal user tries to run a dev command, it will return 1, which means it wont run and their met with a fail message)\n\n##### Example\n\nHere i define a command with the custom property `canBeServerDisabled`\n\n```js\nconst {SlashCommandManager} = require(\"ic4d\");\nconst {SlashCommandBuilder} = require(\"discord.js\");\n\nconst rob = new SlashCommandManager({\n    data: new SlashCommandBuilder()\n        .setName(\"rob\")\n        .setDescription(\"Rob users\")\n    execute: (interaction, client) =\u003e {\n        interaction.reply(\"bang bang!\");\n    },\n});\n\nrob.canBeServerDisabled = true;\n\nmodule.exports = rob\n```\n\nAnd in my middleware function i check if the command has been server disabled, if the property is enabled.\n\n```js\nconst isServerDisabled = (name) =\u003e {\n    // check to see if the function has been disabled by the server, if so return true, otherwise false.\n};\n\nconst middleWare = (commandObject, interaction) =\u003e {\n    // you can name the parameters whatever you want, ass long as you remember which one is which.\n    if (\n        commandObject.canBeServerDisabled \u0026\u0026\n        isServerDisabled(commandObject.name)\n    ) {\n        interaction.reply({\n            content: \"This command is server disabled\",\n            ephemeral: true,\n        });\n        return 1;\n    }\n    return 0;\n};\n\nhandler.handleCommands([middleWare]); // pass the function alone without brackets or its parameters, i'll do that magic\n```\n\n# InteractionHandler\n\nHandler to handle interactions.\n\n## Pre-Read\n\nContext Menus work a bit differently then the other interactions, please refer to [registerContextMenus()](#registercontextmenus)\n\n## Constructor\n\n-   `core`**:[CoreHandler](#corehandler)**\n    -   CoreHandler instance.\n-   `path`**: string**\n    -   Path to where interactions are stored.\n-   `loaderOptions`**: [LoaderOptions](#loaderoptions)**\n    -   **(optional)** Context Menu Loader Options\n-   `flags`**: [InteractionHandlerFlags](#interactionhandlerflags)**\n    -   **(optional)** Interaction Handler Flags\n\n```js\nconst { InteractionHandler, CoreHandler } = require(\"ic4d\");\nconst path = require(\"path\");\n\nconst core = new CoreHandler(client, \"./logs\");\n\nconst interactions = new InteractionHandler(\n    core,\n    path.join(__dirname, \"commands\")\n);\n```\n\n## Methods\n\n### `start()`\n\nStart listening for all the available interactions. (Context Menus, Buttons, Select Menus and Modals)\n\n-   `authorOnlyMsg`**: string**\n    -   **(optional)** Message to display when a interacts with another user's interaction (onlyAuthor is set to true.)\n-   `...middleWare`**: ((interaction?: [Interaction](https://discord.js.org/docs/packages/discord.js/main/Interaction:TypeAlias)) =\u003e number)[]**\n    -   Functions to run before an interaction is run.\n\n```js\ninteractions.start();\n```\n\n### `buttons()`\n\nStart listening for button interactions.\n\n-   `authorOnlyMsg`**: string**\n    -   **(optional)** Message to display when a user click's another user's button (onlyAuthor is set to true.)\n-   `...middleWare`**: ((interaction?: [Interaction](https://discord.js.org/docs/packages/discord.js/main/Interaction:TypeAlias)) =\u003e number)[]**\n    -   Functions to run before a button is run.\n\n```js\ninteractions.buttons();\n```\n\n### `selectMenus()`\n\nStart listening for select menu interactions.\n\n-   `authorOnlyMsg`**: string**\n    -   **(optional)** Message to display when a user click's another user's select menu (onlyAuthor is set to true.)\n-   `...middleWare`**: ((interaction?: [Interaction](https://discord.js.org/docs/packages/discord.js/main/Interaction:TypeAlias)) =\u003e number)[]**\n    -   Functions to run before a select menu is run.\n\n```js\ninteractions.selectMenu();\n```\n\n### `modals()`\n\nStart listening for modal interactions. (After their registered)\n\n-   `...middleWare`**: ((interaction?: [Interaction](https://discord.js.org/docs/packages/discord.js/main/Interaction:TypeAlias)) =\u003e number)[]**\n    -   Functions to run before a modal is shown.\n\n```js\ninteractions.modals();\n```\n\n### `contextMenus()`\n\nStart listening for context menu interactions. (After their registered)\n\n-   `...middleWare`**: ((interaction?: [Interaction](https://discord.js.org/docs/packages/discord.js/main/Interaction:TypeAlias)) =\u003e number)[]**\n    -   Functions to run before a context menu is run.\n\n```js\ninteractions.contextMenus();\n```\n\n#### Interactions Middleware\n\nExactly like [Command Middleware](#middleware-parameters-and-use), where 1 will return and any number will continue execution. Only difference is here the only parameter you get is interaction.\n\n#### Example\n\n```js\nfunction isAuthor(interaction) {\n    // the handler does this for you (check the InteractionObject) but im writing this as an example only.\n    const author = interaction.message.interaction.user.id;\n    const clicker = interaction.member.user.id;\n\n    return clicker === author ? 1 : 0;\n}\nfunction lucky(interaction) {\n    // randdom one\n    return 1 == 1 ? 1 : 0; // will always return 1.\n}\n\n// some other code\n\ninteractions.buttons(\"This isn't your button!\", isAuthor); // this will only run for buttons.\ninteractions.start(undefined, lucky); // will run for every interactions\n```\n\n### `registerContextMenus()`\n\n**(asynchronous function)**\n\nRegisters Context Menus that are found in the path given tot he InteractionHandler.\n\n-   `logAll`**: string**\n    -   **(optional)** Log context menu even if no change was performed.\n-   `serverId`**: string**\n    -   **(optional)** Register all commands in a specific server. if not provided it will be application wide\n\n```js\nawait interactions.registerContextMenus();\n```\n\n# SlashCommandManager\n\nThis class represents a single command that is immediately exported from a file in the `\"commands\"` directory of your choosing\n\n\u003e [!NOTE] Methods can be chained together\n\nExmaple:\n\n```js\nconst { SlashCommandManager } = require(\"ic4d\");\n\nconst command = new SlashCommandManager();\n\nmodule.exports = command;\n```\n\n## Constructor\n\n-   `commandObject`**: {\n    data: [SlashCommandBuilder](https://discord.js.org/docs/packages/builders/1.8.2/SlashCommandBuilder:Class);\n    execute: (\n    interaction: [ChatInputCommandInteraction](https://discord.js.org/docs/packages/discord.js/main/ChatInputCommandInteraction:Class),\n    client?: [Client](https://discord.js.org/docs/packages/discord.js/main/Client:Class),\n    addInteractionVariables?: (k: { [key: string]: any }) =\u003e void\n    ) =\u003e void | Promise\\\u003cvoid\u003e**\n    -   Command's data, Only takes in 2 properties: `data` property which contains the command's data from the discord.js provided class `SlashCommandBuilder` and the `execute` property which takes in a function with the `interaction` and `client` parameter.\n    -   `addInteractionVaribles` is a function that can be used in the execute method to pass variables to buttons, modals and select menus (See [here](#addinteractionvariables-method-3))\n\nExample:\n\n```js\nconst { SlashCommandManager } = require(\"ic4d\");\n\nconst command = new SlashCommandManager({\n    data: new SlashCommandBuilder()\n        .setName(\"ping\")\n        .setDescription(\"Pong!\")\n        .addAttachmentOption((option) =\u003e\n            option.setName(\"user\").setDescription(\"Ping a user for no reason.\")\n        ),\n    execute: (interaction, client) =\u003e {\n        interaction.reply(\"pong!!\");\n    },\n});\n\nmodule.exports = command;\n```\n\n## Methods\n\n### `setUserPermissions`\n\nSets the permissions required by the user to execute the command.\n\n-   `...perms`**: bigint[]**\n    -   Rest paramter of `bigint`s provided by discord.js ([PermissionFlagsBits](https://discord-api-types.dev/api/discord-api-types-payloads/common#PermissionFlagsBits))\n\n**_`returns`: [self](#slashcommandmanager)_**\n\nExample:\n\n```js\nconst { SlashCommandManager } = require(\"ic4d\");\nconst { PermissionFlagsBits } = require(\"discord.js\");\n\nconst command = new SlashCommandManager(/* command cofig */).setUserPermissions(\n    PermissionFlagsBits.Administrator\n);\nmodule.exports = command;\n```\n\n### `setBotPermissions`\n\nSets the permissions needed for the bot to execute the command.\n\n-   `...perms`**: bigint[]**\n    -   Rest paramter of `bigint`s provided by discord.js ([PermissionFlagsBits](https://discord-api-types.dev/api/discord-api-types-payloads/common#PermissionFlagsBits))\n\n**_`returns`: [self](#slashcommandmanager)_**\n\nExample:\n\n```js\nconst { SlashCommandManager } = require(\"ic4d\");\nconst { PermissionFlagsBits } = require(\"discord.js\");\n\nconst command = new SlashCommandManager(/* command cofig */).setBotPermissions(\n    PermissionFlagsBits.Administrator\n);\nmodule.exports = command;\n```\n\n### `setDeleted`\n\nSets the commmand to be deleted, If command has already been deleted, it will be skipped when loaded again.\n\n-   `bool`**: boolean**\n    -   Boolean param\n\n**_`returns`: [self](#slashcommandmanager)_**\n\nExample:\n\n```js\nconst { SlashCommandManager } = require(\"ic4d\");\n\nconst command = new SlashCommandManager(/* command cofig */).setDeleted(true);\nmodule.exports = command;\n```\n\n### `addInteractions`\n\nAppends related interactions to the slash command, only way for slash commands and other interactions to appear in the same file.\n\n-   `...interactions`**: [InteractionBuilder](#interactionbuilder)[]**\n    -   Rest paramater of [InteractionBuilder](#interactionbuilder)\n\n**_`returns`: [self](#slashcommandmanager)_**\n\n```js\nconst { SlashCommandManager, InteractionBuilder } = require(\"ic4d\");\n\nconst command = new SlashCommandManager(/* command cofig */).addInteractions(\n    new InteractionBuilder() /*...*/\n);\nmodule.exports = command;\n```\n\n# InteractionBuilder\n\nRepresents a single interaction that isn't a chat input (slash command) or context menu. (This class can however be passed into a rest parameter in [SlashCommandManager](#slashcommandmanager) or in it's own separate file by itself.)\nBuilder for Context Menus: [ContextMenuBuilder](#contextmenubuilder)\n\n\u003e [!NOTE] Methods can be chained together\n\nExample:\n\n```js\nconst { InteractionBuilder } = require(\"ic4d\");\n\nconst button = new InteractionBuilder()\n    .setCustomId(\"button-1\")\n    .setType(\"button\")\n    .setCallback((i) =\u003e {\n        i.update(\"whats up\");\n    })\n    .setOnlyAuthor(true);\n```\n\n## Constructor\n\nNo parameters are passed, so no documentation :)\nyay. (I hate documenting.)\n\n## Methods\n\n### `setCustomId`\n\nSets the custom ID of the interaction.\n\n-   `customId`**: string**\n    -   Custom ID of the interaction.\n\n**_`returns`: [self](#interactionbuilder)_**\n\n```js\nconst button = new InteractionBuilder().setCustomId(\"my-cool-button\");\n```\n\n### `setType`\n\nSets the type of the interaction. (Either \"selectMenu\", \"button\" or \"modal\")\n\n-   `type`: [InteractionTypeStrings](#interactiontypestrings)\n    -   Type of the interaction.\n\n**_`returns`: [self](#interactionbuilder)_**\n\n```js\nconst selectMenu = new InteractionBuilder().setType(\"selectMenu\");\n```\n\n### `setCallback`\n\nFunction to be called when the interaction is called. (Is that how you say it?)\n\n-   `fn`**: (\n    interaction: [InteractionTypeStringsMap\u003cthis[\"type\"]\u003e](#interactiontypestringsmap),\n    client?: [Client](https://discord.js.org/docs/packages/discord.js/main/Client:Class),\n    variables?: { [key:string]: any }\n    ) =\u003e void | Promise\\\u003cvoid\u003e**\n    -   The function to be called (Parameters: `(interaction, client, variables)`)\n    -   (See [here](#addinteractionvariables-method-3) for variables param)\n\n**_`returns`: [self](#interactionbuilder)_**\n\n```js\nconst selectMenu = new InteractionBuilder().setCallback((i) =\u003e {\n    i.update(\"Client parameter is optional\");\n});\n```\n\n### `setOnlyAuthor`\n\nSet whether or not the interaction can only be interacted with by the author of the interaction.\n\n-   `bool`**: boolean**\n    -   If true, the interaction only accepts the author's input.\n\n**_`returns`: [self](#interactionbuilder)_**\n\n```js\nconst button = new InteractionBuilder().setOnlyAuthor(true);\n```\n\n### `setTimeout`\n\nSets the interaction to have a timeout.\n\n-   `fn`**:(\n    interaction: [ChatInputCommandInteraction](https://discord.js.org/docs/packages/discord.js/main/ChatInputCommandInteraction:Class),\n    client?: [Client](https://discord.js.org/docs/packages/discord.js/main/Client:Class),\n    variables?: { [key:string]: any }\n    ) =\u003e void | Promise\\\u003cvoid\u003e**\n    -   Function to call when the interaction time expires.\n    -   (See [here](#addinteractionvariables-method-3) for variables param)\n-   `timeout`**: number**\n    -   How long to wait for the interaction to timeout. (in ms)\n\n**_`returns`: [self](#interactionbuilder)_**\n\n```js\nconst a = new InteractionBuilder().setTimeout((i) =\u003e {\n    i.editReply(\"Damn the time expired brodie\");\n}, 10_000);\n```\n\n# ContextMenuBuilder\n\nBuilder for context menus, since they are special.\n\n## Constructor\n\n-   `context`**: {\n    data: [ContextMenuCommandBuilder](https://discord.js.org/docs/packages/builders/main/ContextMenuCommandBuilder:Class);\n    execute: (\n    interaction: [ContextMenuCommandInteraction](https://discord.js.org/docs/packages/discord.js/main/ContextMenuCommandInteraction:Class),\n    client?: [Client](https://discord.js.org/docs/packages/discord.js/main/Client:Class)\n    ) =\u003e void;\n    }**\n    -   Object with 2 properties, a `data` property that is an instance of `ContextMenuBuilder` provided by discord.js and a function called `execute` to execute when the context menu is called.\n\n```js\nconst {\n    ApplicationCommandType,\n    ContextMenuCommandBuilder,\n} = require(\"discord.js\");\nconst { ContextMenuBuilder } = require(\"ic4d\");\n\nconst user = new ContextMenuBuilder({\n    data: new ContextMenuCommandBuilder()\n        .setName(\"Get User Avatar\")\n        .setType(ApplicationCommandType.User),\n    execute: (interaction, client) =\u003e {\n        const user = interaction.targetUser;\n\n        interaction.reply({\n            ephemeral: true,\n            content: user.displayAvatarURL(),\n        });\n    },\n});\n\nmodule.exports = user;\n```\n\n## Methods\n\n### `setDeleted`\n\nSets the context menu to be deleted, If context menu has already been deleted, it will be skipped when loaded again.\n\n-   `deleted`**: boolean**\n    -   Boolean indicating whether the context menu is deleted.\n\n**_`returns`: [self](#contextmenubuilder)_**\n\n```js\nconst user = new ContextMenuBuilder().setDeleted(true);\n```\n\n# RunFlags\n\nAn interface representing the configuration flags used for running commands in the bot.\n\nThis configuration is specifically used to control various runtime aspects of command execution.\n\n## Properties\n\n### **_testGuildId: string_**\n\n```\nDefault value: undefined\n```\n\nThe ID of the test guild for command testing purposes. If provided, commands will be deployed only to this guild.\n\n### **_devs: string[]_**\n\n```\nDefault value: []\n```\n\nAn array of Discord user IDs (snowflakes) that have developer privileges.\n\nCommands or functionalities restricted to developers will be accessible to users with IDs in this array.\n\n### **_onlyDev: string_**\n\n```\nDefault value: \"Only developers are allowed to run this command.\"\n```\n\nThe message shown when a command restricted to developers is executed by a non-developer.\n\n### **_userNoPerms: string_**\n\n```\nDefault value: \"Not enough permissions.\"\n```\n\nThe message displayed when a user lacks the necessary permissions to execute a command.\n\n### **_botNoPerms: string_**\n\n```\nDefault value: \"I don't have enough permissions.\"\n```\n\nThe message displayed when the bot lacks the necessary permissions to execute a command.\n\n## Exmaple Use\n\n```ts\nconst obj: RunFlags = {\n    testGuildId: \"808701451399725116\",\n    devs: [\"671549251024584725\"],\n\n    onlyDev: \"Text to display when a user runs a developer command.\",\n    userNoPerms: \"Text to display when the user has insufficient permissions\",\n    botNoPerms: \"Text to display when the bot has insufficient permissions\",\n};\n```\n\n# HandlerFlags\n\nAn interface that represents anything you can do with the commands when they are run, BUT before YOUR code executes.\n\n## Properties\n\n### **_debugger: boolean_**\n\n```\nDefault value: false\n```\n\nEnable debugger mode. Prints(almost) everything that happens behind the scenes of course not with the API itself.\n\n### **_disableLogs: boolean_**\n\n```\nDefault value: false\n```\n\nDisabling Logging of the Command Loader. Not advisable but hey it's your bot.\n\n### **_production: boolean_**\n\n```\nDefault value: false\n```\n\nWhether or not this is the production version of the bot. If set to true, commands labelled `isDev` will NOT be loaded. (Use the `setDev()` method in [SlashCommandManager](#slashcommandmanager))\n\n### **_refreshApplicationCommands: boolean_**\n\n```\nDefault value: false\n```\n\nClears ALL application commands on startup. (Slash commands, User commands, and Message commands.)\n\n### **_logToFolder: string | false_**\n\n```\nDefault value: (CoreHandler value) or false\n```\n\nWhen debugger mode is enabled, Either log to console or a file.\n\n## Example Use\n\n```ts\nconst obj: LoaderOptions = {\n    debugger: true,\n    production: true,\n    disableLogs: true,\n};\n```\n\n# InteractionHandlerFlags\n\nAn interface that represents anything you can do with the interactions when they are run, BUT before YOUR code executes.\n\n## Properties\n\n### **_debugger: boolean_**\n\n```\nDefault value: false\n```\n\nEnable Debugger mode. Prints (almost) everything that happens behind the scenes of course not with the API itself.\n\n### **_disableLogs: boolean_**\n\n```\nDefault value: false\n```\n\nDisabling Logging of the Context Menu Loader. Not advised but hey it's your bot. Default is false.\n\n### **_refreshContextMenus: boolean_**\n\n```\nDefault value: false\n```\n\nClears Context Menus\n\n### **_logToFolder: string | false_**\n\n```\nDefault value: (CoreHandler value) or false\n```\n\nWhen debugger mode is enabled, Either log to console or a file.\n\n# LoaderOptions\n\nInterface that represents default string values for the loader to log to the console when it encounters a command/context menu.\n\nMake sure you keep `NAME` in the string or else you will not know what happened to which command.\nIf there is no log in the console for a specific command, then it has been loaded, there are no edits and it has not been deleted.\n\n## Properties\n\nNote:\n\n\u003e These have multiple default values, as context menus and commands are different.\n\n### **_loaded: string_**\n\nWhat to show for context menus/commands that load in\n\n### **_edited: string_**\n\nWhat to show for context menus/commands that gets edited.\n\n### **_deleted: string_**\n\nWhat to show for context menus/commands that gets deleted.\n\n### **_skipped: string_**\n\nWhat to show for context menus/commands that gets skipped. (Deleted and still marked as deleted.)\n\n### **_loadedNoChanges: string_**\n\nWhat to show for context menus/commands that gets loaded, but has no changes\n\n## Example Use\n\n```ts\nconst obj: LoaderOptions = {\n    loadedNoChanges: \"NAME was loaded. No changes were made to NAME.\",\n    loaded: \"NAME has been registered successfully.\",\n    edited: \"NAME has been edited.\",\n    deleted: \"NAME has been deleted.\",\n    skipped: \"NAME was skipped. (Command deleted or set to delete.)\",\n};\n```\n\n# InteractionTypeStrings\n\nType alias for the strings `\"selectMenu\"`, `\"modal\"` and `\"button\"`\n\nYes this did not need documenting, but here it is.\n\n# InteractionTypeStringsMap\n\nHere's the exact definition because I genuinely don't know how to explain this.\n\n```ts\nexport type InteractionTypeStringsMap\u003cU extends string\u003e = U extends \"modal\"\n    ? ModalSubmitInteraction\n    : U extends \"selectMenu\"\n    ? AnySelectMenuInteraction\n    : U extends \"button\"\n    ? ButtonInteraction\n    : never;\n```\n\n# Common Problems\n\n## Sharding\n\nThis is the exact same code from [Quick Example](#quick-example) except it's sharding compatible\n\n```js\nrequire(\"dotenv\").config();\nconst { Client, IntentsBitField, ShardingManager } = require(\"discord.js\");\nconst path = require(\"path\");\n\nconst { CommandHandler, ReadyHandler, CoreHandler } = require(\"ic4d\");\n\nconst commandsPath = path.join(__dirname, \"..\", \"commands\");\nconst logPath = path.join(__dirname, \"..\", \"logs\");\n\nconst runFlags = {\n    devs: [\"671549251024584725\"],\n    testGuildId: \"808701451399725116\",\n};\n\n// Use ShardingManager to manage shards\nconst manager = new ShardingManager(__filename, {\n    token: process.env.TOKEN,\n    totalShards: \"auto\", // Discord.js will automatically decide shard count\n});\n\nmanager.on(\"shardCreate\", (shard) =\u003e {\n    console.log(`Shard ${shard.id} launched.`);\n});\n\n// Core bot logic for each shard\nif (!process.env.SHARDING_MANAGER) {\n    const client = new Client({\n        intents: [\n            IntentsBitField.Flags.Guilds,\n            IntentsBitField.Flags.GuildMessages,\n        ],\n    });\n\n    const core = new CoreHandler(client, logPath);\n\n    const ready = new ReadyHandler(\n        core\n        async (shardClient) =\u003e {\n            console.log(`${shardClient.user.tag} is ready!`);\n        },\n        async () =\u003e {\n            await handler.registerCommands();\n        }\n    );\n\n    const handler = new CommandHandler(\n        core,\n        commandsPath,\n        runFlags\n    );\n\n    (async () =\u003e {\n        await client.login(process.env.TOKEN);\n        ready.execute();\n        await handler.handleCommands();\n    })();\n}\n\n// Launch all shards\nmanager.spawn();\n```\n\n## Sharing variables between slash and interactions\n\n-   Example: You have where a variable needs to be shared from the slash command callback to the interaction callback. Here there are 3 methods (1 being the recommended approach)\n\n### Method 1 \u0026 2 (Not recommended)\n\nMethod 1 involves:\n\n\u003e Setting and retrieving an outside variable which the slash and interaction callback can receive\n\nMethod 2 involves:\n\n\u003e Adding a property to the slash command object itself and retrieving that property later in the interaction callback.\n\n```js\n// method 1\nlet variable = \"\";\n\nconst test = new SlashCommandManager({\n    data: new SlashCommandBuilder()\n        .setName(\"test\")\n        .setDescription(\"Just a test\")\n        .addStringOption((option) =\u003e\n            option\n                .setName(\"string\")\n                .setDescription(\"some input\")\n                .setRequired(true)\n        ),\n\n    async execute(interaction, client) {\n        try {\n            await interaction.deferReply();\n            const itemName = interaction.options.get(\"string\").value;\n\n            // method 1 (global variable)\n            variable = itemName;\n\n            // method 2 (adding a property)\n            test.variable = itemName;\n\n            await interaction.editReply({\n                content: \"Huh?\",\n                components: [\n                    new ActionRowBuilder().addComponents(\n                        new ButtonBuilder()\n                            .setCustomId(\"hello\")\n                            .setLabel(\"click now\")\n                            .setStyle(ButtonStyle.Primary)\n                    ),\n                ],\n            });\n        } catch (e) {\n            errorHandler(e, client, interaction, EmbedBuilder);\n        }\n    },\n}).addInteractions(button);\n\nconst button = new InteractionBuilder()\n    .setType(\"button\")\n    .setCustomId(\"hello\")\n\n    .setCallback(async (i, c) =\u003e {\n        // method 1\n        const itemName = variable;\n\n        //method 2\n        const itemName = test.variable;\n        await i.update({ content: itemName, components: [] });\n    });\n\nmodule.exports = test;\n```\n\nMethod 1 issue:\n\n\u003e **Concurrency issues:** The main problem with this method is that if multiple users run the command simultaneously, the variable is overwritten by the most recent execution. This means that data intended for one user could be exposed or altered by another user’s command, leading to unexpected behavior and security issues.\n\nMethod 2 issue(s):\n\n\u003e **Shared State:** Although this method keeps the variable associated with the specific command object, it still doesn't address the issue of multiple users running the command. If two users execute the command, the stored value will change to reflect the most recent one, causing similar issues to the global variable method.\n\u003e\n\u003e **Not Scoped Per Interaction:** This approach doesn’t effectively isolate variables for individual interactions, which can lead to data being inadvertently shared between users.\n\n### addInteractionVariables() (method 3)\n\nThis uses a new function passed into [SlashCommandManager execute function (in the constructor object)](#constructor-3), which you can use to pass anything to the interactions associated with this command.\n(Returns void);\n\n-   `k`**: { [key: string]: any }**\n    -   Object of variables to save and be referenced later in interactions associated with this command.\n\nThen to use these variables, in either the [setCallback](#setcallback) or [setTimeout](#settimeout) method of the [InteractionBuilder](#interactionbuilder), add the optional parameter `variables` which returns the object you passed (hopefully)\n\nExample:\n\n```js\nconst test = new SlashCommandManager({\n    data: new SlashCommandBuilder()\n        .setName(\"test\")\n        .setDescription(\"Just a test\")\n        .addStringOption((option) =\u003e\n            option\n                .setName(\"string\")\n                .setDescription(\"some input\")\n                .setRequired(true)\n        ),\n    // here we add the function in the parameter list\n    async execute(interaction, client, addInteractionVariables) {\n        try {\n            await interaction.deferReply();\n            const itemName = interaction.options.get(\"string\").value;\n            await interaction.editReply({\n                content: \"Huh?\",\n                components: [\n                    new ActionRowBuilder().addComponents(\n                        new ButtonBuilder()\n                            .setCustomId(\"hello\")\n                            .setLabel(\"click now\")\n                            .setStyle(ButtonStyle.Primary)\n                    ),\n                ],\n            });\n\n            // using the function\n            addInteractionVariables({ itemName });\n        } catch (e) {\n            errorHandler(e, client, interaction, EmbedBuilder);\n        }\n    },\n}).addInteractions(button);\n\nconst button = new InteractionBuilder()\n    .setType(\"button\")\n    .setCustomId(\"hello\")\n\n    // add the variables to the parameter list\n    .setCallback(async (i, c, variables) =\u003e {\n        // using the variable in the callback\n        await i.update({ content: variables.itemName, components: [] });\n    });\n```\n\nThis method will always find the variables associated with the message sent by the bot. (This method may not work if you have something like a modal before a bot response as it uses the messageId as a unique identifier.)\n\n\u003e **(Better explanation)** `addInteractionVariables()` function ties variables to unique message Ids AND the custom IDs of the slash command, ensuring that data remains scoped to specific interactions and is not shared or overwritten between users. This approach enhances data safety by preventing concurrency issues and ensuring only the relevant interaction can access its data. It also sorta simplifies the process of passing data between commands and interactions\n\nIf any of the approaches don't help your use case. It's always best to just use [Message collectors](https://discordjs.guide/popular-topics/collectors)\n\n## CommandHandler Reading the wrong files\n\n-   Example: This function is in the `commands` direcotory as it is used by multiple commands, but is not a commands itself.\n\n    ```js\n    const function a(userBalance) {\n        return userBalance \u003e 0 ? true : false;\n    }\n\n    module.exports = a;\n    ```\n\n    -   The Command Reader will try to read it but error as it is not a command it can read, to avoid this, make sure you export the `isCommand` (Set to false) property with the function.\n\n    ```js\n    const function a(userBalance) {\n        return userBalance \u003e 0 ? true : false;\n    }\n\n    module.exports = {a, isCommand = false};\n    ```\n\n    -   Usually, the reader should skip over anything it can't read, but if needed, this will immediately make it skip.\n\n# Credits\n\nHuge credit to [underctrl](https://github.com/notunderctrl), Code would've not been possible if i did not watch his helpful discord.js tutorials! I had to give him credit because this package is based off moving all those files fromm his tutorial into one package.\n\nHe probably has a way better package, so go check his out!\n\n# Links\n\n-   [Github](https://github.com/YetNT/ic4d)\n-   [NPM](https://www.npmjs.com/package/ic4d)\n-   [underctrl Discord.js Tutorial](https://www.youtube.com/playlist?list=PLpmb-7WxPhe0ZVpH9pxT5MtC4heqej8Es)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyetnt%2Fic4d","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyetnt%2Fic4d","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyetnt%2Fic4d/lists"}