honocord 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +495 -0
- package/dist/index.d.mts +686 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +906 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 The-LukeZ
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
# HonoCord
|
|
2
|
+
|
|
3
|
+
A Discord interaction handler library for [Hono](https://hono.dev/), designed to work seamlessly with Cloudflare Workers and other edge runtimes.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🔥 Built on top of Hono for maximum performance
|
|
8
|
+
- ⚡ Perfect for Cloudflare Workers and edge runtimes
|
|
9
|
+
- 🎯 Type-safe interaction handlers
|
|
10
|
+
- 🔐 Built-in request verification
|
|
11
|
+
- 🎨 Support for all Discord interaction types:
|
|
12
|
+
- Slash commands with autocomplete
|
|
13
|
+
- User and Message context menu commands
|
|
14
|
+
- Message components (buttons, select menus)
|
|
15
|
+
- Modal submissions
|
|
16
|
+
- 🗂️ Prefix-based routing for components and modals
|
|
17
|
+
- 📦 Minimal dependencies using `@discordjs/core` and `@discordjs/builders`
|
|
18
|
+
|
|
19
|
+
<small>Yes, AI helped me build this. With the focus on **helped**.</small>
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pnpm install honocord @discordjs/core @discordjs/builders @discordjs/rest discord-api-types
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { Honocord, SlashCommandHandler } from "honocord";
|
|
31
|
+
|
|
32
|
+
const bot = new Honocord();
|
|
33
|
+
|
|
34
|
+
// Define a slash command
|
|
35
|
+
const pingCommand = new SlashCommandHandler().setName("ping").setDescription("Replies with Pong!");
|
|
36
|
+
|
|
37
|
+
// Add handler to the command
|
|
38
|
+
pingCommand.handler = async (interaction) => {
|
|
39
|
+
await interaction.reply("Pong! 🏓");
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Register handlers
|
|
43
|
+
bot.loadHandlers(pingCommand);
|
|
44
|
+
|
|
45
|
+
// Export the app
|
|
46
|
+
export default bot.getApp();
|
|
47
|
+
|
|
48
|
+
// Or use with your own Hono app
|
|
49
|
+
import { Hono } from "hono";
|
|
50
|
+
|
|
51
|
+
const app = new Hono();
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Usage with and without Cloudflare Workers
|
|
55
|
+
|
|
56
|
+
Hono, well rather CF Workers, have a small issue with responding to interactions.
|
|
57
|
+
|
|
58
|
+
When using HonoCord in a Cloudflare Worker environment, you should ensure that your environment variable `IS_CF_WORKER` is set to `"true"` **or** you pass this information to HonoCord in the constructor:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
const bot = new Honocord({ isCFWorker: true }); // true indicates CF Worker environment
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
<details>
|
|
65
|
+
<summary>Why that is needed?</summary>
|
|
66
|
+
|
|
67
|
+
On Cloudflare Workers, we need to make use of `c.executionContext.waitUntil()` to handle asynchronous tasks properly without blocking the response. By checking for the `IS_CF_WORKER` environment variable, HonoCord can determine if it's running in a Cloudflare Worker environment and adjust its behavior accordingly.
|
|
68
|
+
|
|
69
|
+
This approach allows HonoCord to maintain compatibility with both Cloudflare Workers and other environments, ensuring that interactions are handled correctly regardless of where the code is executed.
|
|
70
|
+
|
|
71
|
+
</details>
|
|
72
|
+
|
|
73
|
+
> [!IMPORTANT]
|
|
74
|
+
> This readme assumes you are using Cloudflare Workers.
|
|
75
|
+
> Most stuff is the same for other environments, but keep in mind the `IS_CF_WORKER` variable and the way you export and use your Hono app.
|
|
76
|
+
|
|
77
|
+
## Philosophy - How It Works
|
|
78
|
+
|
|
79
|
+
HonoCord leverages Hono's lightweight and fast request handling capabilities to process Discord interactions efficiently. It verifies incoming requests using Discord's public key, ensuring security and authenticity.
|
|
80
|
+
|
|
81
|
+
To handle interactions, you define various handler types (slash commands, context commands, components, modals) and register them with the `Honocord` instance. Each handler processes its respective interaction type.
|
|
82
|
+
|
|
83
|
+
### Custom IDs
|
|
84
|
+
|
|
85
|
+
Custom IDs for components and modals use a **prefix-based routing system**, allowing you to easily manage multiple interactions with shared logic.
|
|
86
|
+
|
|
87
|
+
Custom IDs follow the pattern: `prefix/component/path?param1/param2`
|
|
88
|
+
|
|
89
|
+
As you can see, it is basically split into two parts: a **path** and **parameters**.
|
|
90
|
+
Both parts are separated by a `?`, and each part is further divided by `/` (every path-segment and param). However, the `prefix` defines which handler will process the interaction.
|
|
91
|
+
|
|
92
|
+
Use the `parseCustomId` utility to parse custom IDs:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { parseCustomId } from "honocord";
|
|
96
|
+
|
|
97
|
+
// Example: "approve/user/request?user123/action456"
|
|
98
|
+
const parsed = parseCustomId("approve/user/request?user123/action456");
|
|
99
|
+
|
|
100
|
+
console.log(parsed.prefix); // "approve"
|
|
101
|
+
console.log(parsed.component); // "user"
|
|
102
|
+
console.log(parsed.lastPathItem); // "request"
|
|
103
|
+
console.log(parsed.compPath); // ["approve", "user", "request"]
|
|
104
|
+
console.log(parsed.params); // ["user123", "action456"]
|
|
105
|
+
console.log(parsed.firstParam); // "user123"
|
|
106
|
+
console.log(parsed.lastParam); // "action456"
|
|
107
|
+
|
|
108
|
+
// Get only the prefix
|
|
109
|
+
const prefix = parseCustomId("approve/user/request?user123", true); // "approve"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Handlers
|
|
113
|
+
|
|
114
|
+
### 1. Slash Command Handler
|
|
115
|
+
|
|
116
|
+
Slash commands are the primary way users interact with your bot. They support autocomplete for option values.
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { SlashCommandHandler } from "honocord";
|
|
120
|
+
|
|
121
|
+
const searchCommand = new SlashCommandHandler()
|
|
122
|
+
.setName("search")
|
|
123
|
+
.setDescription("Search for something")
|
|
124
|
+
.addStringOption((option) =>
|
|
125
|
+
option.setName("query").setDescription("What to search for").setRequired(true).setAutocomplete(true)
|
|
126
|
+
)
|
|
127
|
+
.handler(async (interaction) => {
|
|
128
|
+
const query = interaction.options.getString("query", true);
|
|
129
|
+
await interaction.reply(`Searching for: ${query}`);
|
|
130
|
+
})
|
|
131
|
+
.autocomplete(async (interaction) => {
|
|
132
|
+
const focusedValue = interaction.options.getFocused();
|
|
133
|
+
const choices = ["apple", "banana", "cherry", "dragon fruit", "elderberry"]
|
|
134
|
+
.filter((choice) => choice.startsWith(focusedValue.toLowerCase()))
|
|
135
|
+
.slice(0, 25); // Discord limits to 25 choices
|
|
136
|
+
|
|
137
|
+
await interaction.respond(choices.map((choice) => ({ name: choice, value: choice })));
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
bot.loadHandlers(searchCommand);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 2. Context Command Handler
|
|
144
|
+
|
|
145
|
+
Context commands appear in the right-click menu for users or messages.
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
import { ContextCommandHandler } from "honocord";
|
|
149
|
+
import { ApplicationCommandType } from "discord-api-types/v10";
|
|
150
|
+
|
|
151
|
+
// User context command
|
|
152
|
+
const userInfoCommand = new ContextCommandHandler().setName("User Info").setType(ApplicationCommandType.User);
|
|
153
|
+
|
|
154
|
+
userInfoCommand.handler = async (interaction) => {
|
|
155
|
+
const user = interaction.targetUser;
|
|
156
|
+
await interaction.reply(`User: ${user.username} (${user.id})`);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Message context command
|
|
160
|
+
const translateCommand = new ContextCommandHandler().setName("Translate").setType(ApplicationCommandType.Message);
|
|
161
|
+
|
|
162
|
+
translateCommand.handler = async (interaction) => {
|
|
163
|
+
const message = interaction.targetMessage;
|
|
164
|
+
await interaction.reply(`Translating: "${message.content}"`);
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
bot.loadHandlers(userInfoCommand, translateCommand);
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### 3. Component Handler
|
|
171
|
+
|
|
172
|
+
Component handlers handle interactions from buttons, select menus, and other message components. They use a **prefix-based routing system**.
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import { ComponentHandler } from "honocord";
|
|
176
|
+
import { ButtonBuilder, ButtonStyle, ActionRowBuilder } from "@discordjs/builders";
|
|
177
|
+
|
|
178
|
+
// Create a button with a custom_id using a prefix
|
|
179
|
+
const button = new ButtonBuilder()
|
|
180
|
+
.setCustomId("approve/user123") // prefix: "approve"
|
|
181
|
+
.setLabel("Approve")
|
|
182
|
+
.setStyle(ButtonStyle.Success);
|
|
183
|
+
|
|
184
|
+
// Handler for all components with the "approve" prefix
|
|
185
|
+
const approveHandler = new ComponentHandler("approve", async (interaction) => {
|
|
186
|
+
// Parse the custom_id to get parameters
|
|
187
|
+
const { params } = parseCustomId(interaction.customId);
|
|
188
|
+
const userId = params[0]; // "user123"
|
|
189
|
+
|
|
190
|
+
await interaction.reply(`Approved user: ${userId}`);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
bot.loadHandlers(approveHandler);
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### 4. Modal Handler
|
|
197
|
+
|
|
198
|
+
Modal handlers process form submissions. Like components, they use prefix-based routing.
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
import { ModalHandler } from "honocord";
|
|
202
|
+
import { ModalBuilder, TextInputBuilder, TextInputStyle, ActionRowBuilder } from "@discordjs/builders";
|
|
203
|
+
|
|
204
|
+
// Create a modal
|
|
205
|
+
const modal = new ModalBuilder()
|
|
206
|
+
.setCustomId("feedback/feature") // prefix: "feedback"
|
|
207
|
+
.setTitle("Feature Feedback");
|
|
208
|
+
|
|
209
|
+
const input = new TextInputBuilder()
|
|
210
|
+
.setCustomId("feedback_text")
|
|
211
|
+
.setLabel("What would you like to see?")
|
|
212
|
+
.setStyle(TextInputStyle.Paragraph)
|
|
213
|
+
.setRequired(true);
|
|
214
|
+
|
|
215
|
+
modal.addComponents(new ActionRowBuilder().addComponents(input));
|
|
216
|
+
|
|
217
|
+
// Handler for all modals with the "feedback" prefix
|
|
218
|
+
const feedbackHandler = new ModalHandler("feedback", async (interaction) => {
|
|
219
|
+
const { component } = parseCustomId(interaction.customId);
|
|
220
|
+
const feedbackText = interaction.fields.getTextInputValue("feedback_text");
|
|
221
|
+
|
|
222
|
+
await interaction.reply({
|
|
223
|
+
content: `Thanks for your ${component} feedback: "${feedbackText}"`,
|
|
224
|
+
ephemeral: true,
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
bot.loadHandlers(feedbackHandler);
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Complete Example
|
|
232
|
+
|
|
233
|
+
<details>
|
|
234
|
+
<summary>If you want to only use Honocord for your project and have no existing Hono app:</summary>
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
import { Honocord, SlashCommandHandler, ComponentHandler, ModalHandler } from "honocord";
|
|
238
|
+
|
|
239
|
+
const bot = new Honocord();
|
|
240
|
+
|
|
241
|
+
// Slash command
|
|
242
|
+
const greetCommand = new SlashCommandHandler()
|
|
243
|
+
.setName("greet")
|
|
244
|
+
.setDescription("Sends a greeting")
|
|
245
|
+
.addStringOption((option) => option.setName("name").setDescription("Who to greet").setRequired(true));
|
|
246
|
+
|
|
247
|
+
greetCommand.handler = async (interaction) => {
|
|
248
|
+
const name = interaction.options.getString("name", true);
|
|
249
|
+
await interaction.reply(`Hello, ${name}! 👋`);
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// Component handler for buttons
|
|
253
|
+
const confirmHandler = new ComponentHandler("confirm", async (interaction) => {
|
|
254
|
+
const { params } = parseCustomId(interaction.customId);
|
|
255
|
+
const action = params[0];
|
|
256
|
+
|
|
257
|
+
await interaction.update({
|
|
258
|
+
content: `You confirmed: ${action}`,
|
|
259
|
+
components: [], // Remove buttons
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// Modal handler
|
|
264
|
+
const reportHandler = new ModalHandler("report", async (interaction) => {
|
|
265
|
+
const reason = interaction.fields.getTextInputValue("reason");
|
|
266
|
+
const details = interaction.fields.getTextInputValue("details");
|
|
267
|
+
|
|
268
|
+
await interaction.reply({
|
|
269
|
+
content: "Report submitted successfully!",
|
|
270
|
+
ephemeral: true,
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// Process the report...
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Register all handlers
|
|
277
|
+
bot.loadHandlers(greetCommand, confirmHandler, reportHandler);
|
|
278
|
+
|
|
279
|
+
// For Cloudflare Workers
|
|
280
|
+
export default bot.getApp();
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
</details>
|
|
284
|
+
|
|
285
|
+
or
|
|
286
|
+
|
|
287
|
+
<details>
|
|
288
|
+
<summary>You want to use Honocord with your existing Hono app:</summary>
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
/**
|
|
292
|
+
* Example: Using HonoCord with custom environment types in a Hono app
|
|
293
|
+
*/
|
|
294
|
+
|
|
295
|
+
import { Hono } from "hono";
|
|
296
|
+
import { Honocord, SlashCommandHandler, ComponentHandler } from "honocord";
|
|
297
|
+
import type { BaseHonocordEnv, BaseInteractionContext } from "honocord";
|
|
298
|
+
|
|
299
|
+
// Define your custom bindings
|
|
300
|
+
interface MyBindings {
|
|
301
|
+
DISCORD_TOKEN: string;
|
|
302
|
+
DATABASE: D1Database;
|
|
303
|
+
CACHE: KVNamespace;
|
|
304
|
+
IS_CF_WORKER: "true";
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Create custom environment and context types
|
|
308
|
+
type MyEnv = BaseHonocordEnv<MyBindings>;
|
|
309
|
+
type MyContext = BaseInteractionContext<MyBindings>;
|
|
310
|
+
|
|
311
|
+
// Create Hono app
|
|
312
|
+
const app = new Hono<MyEnv>();
|
|
313
|
+
|
|
314
|
+
// Initialize bot
|
|
315
|
+
const bot = new Honocord();
|
|
316
|
+
|
|
317
|
+
// Create command with type-safe environment access
|
|
318
|
+
const pingCommand = new SlashCommandHandler().setName("ping").setDescription("Ping the bot");
|
|
319
|
+
|
|
320
|
+
pingCommand.handler = async (interaction) => {
|
|
321
|
+
const ctx = interaction.ctx as MyContext;
|
|
322
|
+
|
|
323
|
+
// Type-safe access to bindings
|
|
324
|
+
const cache = ctx.env.CACHE;
|
|
325
|
+
await cache.put("last_ping", new Date().toISOString());
|
|
326
|
+
|
|
327
|
+
await interaction.reply("Pong! 🏓");
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
// Create command that queries database
|
|
331
|
+
const statsCommand = new SlashCommandHandler().setName("stats").setDescription("Show bot stats");
|
|
332
|
+
|
|
333
|
+
statsCommand.handler = async (interaction) => {
|
|
334
|
+
const ctx = interaction.ctx as MyContext;
|
|
335
|
+
const db = ctx.env.DATABASE;
|
|
336
|
+
|
|
337
|
+
const result = await db.prepare("SELECT COUNT(*) as count FROM users").first();
|
|
338
|
+
await interaction.reply(`Total users: ${result?.count ?? 0}`);
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
// Component handler
|
|
342
|
+
const approveButton = new ComponentHandler("approve", async (interaction) => {
|
|
343
|
+
const ctx = interaction.ctx as MyContext;
|
|
344
|
+
const db = ctx.env.DATABASE;
|
|
345
|
+
|
|
346
|
+
// Update database
|
|
347
|
+
await db.prepare("UPDATE requests SET approved = 1").run();
|
|
348
|
+
|
|
349
|
+
await interaction.update({ content: "✅ Approved!" });
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
// Load handlers
|
|
353
|
+
bot.loadHandlers(pingCommand, statsCommand, approveButton);
|
|
354
|
+
|
|
355
|
+
// Interaction endpoint
|
|
356
|
+
app.post("/interactions", (c) => bot.handle(c as MyContext));
|
|
357
|
+
|
|
358
|
+
// Regular API routes
|
|
359
|
+
app.get("/", (c) => c.json({ status: "ok" }));
|
|
360
|
+
|
|
361
|
+
export default app;
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
</details>
|
|
365
|
+
|
|
366
|
+
## Environment Variables
|
|
367
|
+
|
|
368
|
+
```env
|
|
369
|
+
DISCORD_TOKEN=your_bot_token_here
|
|
370
|
+
DISCORD_PUBLIC_KEY=your_public_key_here
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
The `DISCORD_PUBLIC_KEY` is required for request verification and should be available in your environment (e.g., `c.env.DISCORD_PUBLIC_KEY` in Cloudflare Workers).
|
|
374
|
+
|
|
375
|
+
## TypeScript Support
|
|
376
|
+
|
|
377
|
+
HonoCord is written in TypeScript and provides full type safety.
|
|
378
|
+
|
|
379
|
+
### Custom Environment Types
|
|
380
|
+
|
|
381
|
+
```typescript
|
|
382
|
+
import type { BaseHonocordEnv, BaseInteractionContext } from "honocord";
|
|
383
|
+
|
|
384
|
+
// Define your custom environment
|
|
385
|
+
interface MyEnv {
|
|
386
|
+
DISCORD_TOKEN: string;
|
|
387
|
+
DISCORD_PUBLIC_KEY: string;
|
|
388
|
+
DATABASE_URL: string;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Create a custom context type
|
|
392
|
+
type MyContext = BaseInteractionContext<MyEnv>;
|
|
393
|
+
|
|
394
|
+
// Use in your handlers
|
|
395
|
+
const command = new SlashCommandHandler().setName("data").setDescription("Fetch data");
|
|
396
|
+
|
|
397
|
+
command.handler = async (interaction: MyContext) => {
|
|
398
|
+
const dbUrl = interaction.env.DATABASE_URL; // Fully typed!
|
|
399
|
+
// ...
|
|
400
|
+
};
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
## Registering Commands with Discord
|
|
404
|
+
|
|
405
|
+
HonoCord handles command execution, but you still need to register your commands with Discord's API. Here's how:
|
|
406
|
+
|
|
407
|
+
```typescript
|
|
408
|
+
import { REST } from "@discordjs/rest";
|
|
409
|
+
import { Routes } from "discord-api-types/v10";
|
|
410
|
+
|
|
411
|
+
const rest = new REST().setToken(process.env.DISCORD_TOKEN);
|
|
412
|
+
|
|
413
|
+
const commands = [
|
|
414
|
+
pingCommand.toJSON(),
|
|
415
|
+
searchCommand.toJSON(),
|
|
416
|
+
// ... other commands
|
|
417
|
+
];
|
|
418
|
+
|
|
419
|
+
// Register globally (takes up to 1 hour to propagate)
|
|
420
|
+
await rest.put(Routes.applicationCommands(APPLICATION_ID), { body: commands });
|
|
421
|
+
|
|
422
|
+
// Or register for a specific guild (instant)
|
|
423
|
+
await rest.put(Routes.applicationGuildCommands(APPLICATION_ID, GUILD_ID), {
|
|
424
|
+
body: commands,
|
|
425
|
+
});
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
## API Reference
|
|
429
|
+
|
|
430
|
+
### `Honocord`
|
|
431
|
+
|
|
432
|
+
Main class for handling Discord interactions.
|
|
433
|
+
|
|
434
|
+
**Constructor:**
|
|
435
|
+
|
|
436
|
+
- `new Honocord(options?: HonocordOptions)` - Creates a new instance
|
|
437
|
+
|
|
438
|
+
**Methods:**
|
|
439
|
+
|
|
440
|
+
- `loadHandlers(handlers: Handler[])` - Registers interaction handlers
|
|
441
|
+
- `handle(c: Context)` - Hono handler for processing interactions
|
|
442
|
+
- `getApp()` - Returns a pre-configured Hono app instance
|
|
443
|
+
|
|
444
|
+
### `SlashCommandHandler`
|
|
445
|
+
|
|
446
|
+
Extends `SlashCommandBuilder` from `@discordjs/builders`.
|
|
447
|
+
|
|
448
|
+
**Properties:**
|
|
449
|
+
|
|
450
|
+
- `handler: (interaction: ChatInputCommandInteraction) => Promise<void> | void` - Command execution handler
|
|
451
|
+
- `autocomplete?: (interaction: AutocompleteInteraction) => Promise<void> | void` - Optional autocomplete handler
|
|
452
|
+
|
|
453
|
+
### `ContextCommandHandler`
|
|
454
|
+
|
|
455
|
+
Extends `ContextMenuCommandBuilder` from `@discordjs/builders`.
|
|
456
|
+
|
|
457
|
+
**Properties:**
|
|
458
|
+
|
|
459
|
+
- `handler: (interaction: UserCommandInteraction | MessageCommandInteraction) => Promise<void> | void` - Command execution handler
|
|
460
|
+
|
|
461
|
+
### `ComponentHandler`
|
|
462
|
+
|
|
463
|
+
Handler for message components.
|
|
464
|
+
|
|
465
|
+
**Constructor:**
|
|
466
|
+
|
|
467
|
+
- `new ComponentHandler(prefix: string, handler: Function)` - Creates a handler for components with the given prefix
|
|
468
|
+
|
|
469
|
+
### `ModalHandler`
|
|
470
|
+
|
|
471
|
+
Handler for modal submissions.
|
|
472
|
+
|
|
473
|
+
**Constructor:**
|
|
474
|
+
|
|
475
|
+
- `new ModalHandler(prefix: string, handler: Function)` - Creates a handler for modals with the given prefix
|
|
476
|
+
|
|
477
|
+
### `parseCustomId`
|
|
478
|
+
|
|
479
|
+
Utility function for parsing custom IDs.
|
|
480
|
+
|
|
481
|
+
```typescript
|
|
482
|
+
// Get full parsing details
|
|
483
|
+
parseCustomId(customId: string): ParsedCustomId
|
|
484
|
+
|
|
485
|
+
// Get only the prefix
|
|
486
|
+
parseCustomId(customId: string, onlyPrefix: true): string
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
## License
|
|
490
|
+
|
|
491
|
+
MIT
|
|
492
|
+
|
|
493
|
+
## Contributing
|
|
494
|
+
|
|
495
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|