@mostfeatured/dbi 0.2.11 → 0.2.13

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/llm.txt ADDED
@@ -0,0 +1,1088 @@
1
+ # DBI - Discord Bot Infrastructure
2
+
3
+ > The most advanced, modern, and developer-friendly Discord bot framework available.
4
+ > NPM Package: @mostfeatured/dbi
5
+
6
+ ## Overview
7
+
8
+ DBI (Discord Bot Infrastructure) is a powerful NPM module that provides a complete infrastructure for building production-ready Discord bots with minimal boilerplate. It wraps Discord.js v14 and provides type-safe, structured patterns for building scalable bots.
9
+
10
+ ## Key Features
11
+
12
+ - **Slash Commands**: Full support for Discord's application commands with type-safe options
13
+ - **Components V2**: Buttons, Select Menus, Modals with built-in state management
14
+ - **Svelte Integration**: Build reactive Discord UIs with Svelte 5 components
15
+ - **Localization**: Multi-language support for both content and interactions
16
+ - **Message Commands**: Automatic slash-to-message command conversion
17
+ - **Reference System**: Pass complex data through components without database
18
+ - **Rate Limiting**: Built-in per-user, channel, guild rate limiting
19
+ - **Multi-Client**: Support for multiple bot clients simultaneously
20
+ - **Hybrid Sharding**: Built-in support for discord-hybrid-sharding
21
+ - **Type Safety**: Full TypeScript support with intelligent autocomplete
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ npm install @mostfeatured/dbi discord.js
27
+ # or
28
+ pnpm add @mostfeatured/dbi discord.js
29
+ ```
30
+
31
+ ## Project Structure
32
+
33
+ ```
34
+ my-bot/
35
+ ├── dbi.js # DBI configuration
36
+ ├── login.js # Bot startup script
37
+ ├── publish.js # Command publishing script
38
+ └── src/
39
+ ├── commands/ # Slash commands
40
+ ├── events/ # Discord event handlers
41
+ ├── components/ # Buttons, Select Menus, Modals
42
+ └── locales/ # Language files
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Core Concepts
48
+
49
+ ### 1. Creating DBI Instance
50
+
51
+ ```javascript
52
+ const { createDBI } = require("@mostfeatured/dbi");
53
+
54
+ const dbi = createDBI("my-bot", {
55
+ strict: true,
56
+ discord: {
57
+ token: process.env.DISCORD_TOKEN,
58
+ options: {
59
+ intents: ["Guilds", "GuildMessages", "MessageContent"]
60
+ }
61
+ },
62
+ defaults: {
63
+ locale: { name: "en" },
64
+ defaultMemberPermissions: ["SendMessages"],
65
+ directMessages: false
66
+ },
67
+ references: {
68
+ autoClear: {
69
+ ttl: 60 * 60 * 1000, // 1 hour
70
+ check: 60 * 1000 // Check every minute
71
+ }
72
+ },
73
+ inlineListeners: {
74
+ autoClear: {
75
+ ttl: 15 * 60 * 1000, // 15 minutes
76
+ check: 60 * 1000
77
+ }
78
+ }
79
+ });
80
+
81
+ module.exports = dbi;
82
+ ```
83
+
84
+ ### 2. The Register Pattern
85
+
86
+ DBI uses a register pattern to define all bot features:
87
+
88
+ ```javascript
89
+ dbi.register(({ ChatInput, Button, Event, Locale }) => {
90
+ ChatInput({ /* ... */ });
91
+ Button({ /* ... */ });
92
+ Event({ /* ... */ });
93
+ Locale({ /* ... */ });
94
+ });
95
+ ```
96
+
97
+ Available register functions:
98
+ - `ChatInput` - Slash commands
99
+ - `Button` - Button components
100
+ - `StringSelectMenu`, `UserSelectMenu`, `RoleSelectMenu`, `ChannelSelectMenu`, `MentionableSelectMenu` - Select menus
101
+ - `Modal` - Modal dialogs
102
+ - `MessageContextMenu`, `UserContextMenu` - Context menu commands
103
+ - `Event` - Discord events
104
+ - `Locale` - Content localization
105
+ - `InteractionLocale` - Interaction name localization
106
+ - `CustomEvent` - Custom event definitions
107
+ - `HTMLComponentsV2` - Svelte/Eta template components
108
+ - `ChatInputOptions` - Command option builders
109
+ - `onUnload` - Cleanup callback for hot reloading
110
+
111
+ ### 3. Starting the Bot
112
+
113
+ ```javascript
114
+ const { Utils } = require("@mostfeatured/dbi");
115
+ const dbi = require("./dbi");
116
+
117
+ async function start() {
118
+ await Utils.recursiveImport("./src"); // Import all files
119
+ await dbi.load(); // Load features
120
+ await dbi.login(); // Connect to Discord
121
+ }
122
+ start();
123
+ ```
124
+
125
+ ### 4. Publishing Commands
126
+
127
+ ```javascript
128
+ const { Utils } = require("@mostfeatured/dbi");
129
+ const dbi = require("./dbi");
130
+
131
+ async function publish() {
132
+ await Utils.recursiveImport("./src");
133
+ await dbi.load();
134
+
135
+ // Development: Guild-specific (instant)
136
+ await dbi.publish("Guild", "YOUR_GUILD_ID");
137
+
138
+ // Production: Global (up to 1 hour delay)
139
+ // await dbi.publish("Global");
140
+
141
+ await dbi.unload();
142
+ }
143
+ publish();
144
+ ```
145
+
146
+ ---
147
+
148
+ ## Chat Input Commands (Slash Commands)
149
+
150
+ ### Basic Command
151
+
152
+ ```javascript
153
+ dbi.register(({ ChatInput }) => {
154
+ ChatInput({
155
+ name: "ping",
156
+ description: "Check the bot's latency",
157
+ async onExecute({ interaction, dbi }) {
158
+ const latency = dbi.client().client.ws.ping;
159
+ await interaction.reply(`🏓 Pong! Latency: ${latency}ms`);
160
+ }
161
+ });
162
+ });
163
+ ```
164
+
165
+ ### Command Options
166
+
167
+ ```javascript
168
+ dbi.register(({ ChatInput, ChatInputOptions }) => {
169
+ ChatInput({
170
+ name: "greet",
171
+ description: "Greet someone",
172
+ options: [
173
+ ChatInputOptions.user({
174
+ name: "user",
175
+ description: "User to greet",
176
+ required: true
177
+ }),
178
+ ChatInputOptions.string({
179
+ name: "message",
180
+ description: "Custom message",
181
+ required: false,
182
+ minLength: 1,
183
+ maxLength: 200
184
+ }),
185
+ ChatInputOptions.boolean({
186
+ name: "mention",
187
+ description: "Mention the user?",
188
+ required: false
189
+ })
190
+ ],
191
+ onExecute({ interaction }) {
192
+ const user = interaction.options.getUser("user");
193
+ const message = interaction.options.getString("message") || "Hello!";
194
+ const mention = interaction.options.getBoolean("mention");
195
+
196
+ interaction.reply(mention ? `${user} ${message}` : `${user.username}: ${message}`);
197
+ }
198
+ });
199
+ });
200
+ ```
201
+
202
+ ### ChatInputOptions Methods
203
+
204
+ | Method | Description |
205
+ |--------|-------------|
206
+ | `string()` | Free text input |
207
+ | `stringChoices()` | Text with predefined choices |
208
+ | `stringAutocomplete()` | Text with dynamic autocomplete |
209
+ | `integer()` | Whole number |
210
+ | `integerChoices()` | Integer with choices |
211
+ | `integerAutocomplete()` | Integer with autocomplete |
212
+ | `number()` | Decimal number |
213
+ | `numberChoices()` | Number with choices |
214
+ | `numberAutocomplete()` | Number with autocomplete |
215
+ | `boolean()` | True/false |
216
+ | `user()` | User mention |
217
+ | `channel()` | Channel mention (supports `channelTypes[]`) |
218
+ | `role()` | Role mention |
219
+ | `mentionable()` | User or role |
220
+ | `attachment()` | File upload |
221
+
222
+ ### Autocomplete
223
+
224
+ ```javascript
225
+ ChatInputOptions.stringAutocomplete({
226
+ name: "item",
227
+ description: "Search for an item",
228
+ required: true,
229
+ async onComplete({ value, interaction }) {
230
+ const items = await searchDatabase(value);
231
+ return items.slice(0, 25).map(item => ({
232
+ name: item.displayName,
233
+ value: item.id
234
+ }));
235
+ }
236
+ })
237
+ ```
238
+
239
+ ### Subcommands
240
+
241
+ ```javascript
242
+ const Discord = require("discord.js");
243
+
244
+ ChatInput({
245
+ name: "config",
246
+ description: "Bot configuration",
247
+ options: [
248
+ {
249
+ type: Discord.ApplicationCommandOptionType.Subcommand,
250
+ name: "view",
251
+ description: "View configuration"
252
+ },
253
+ {
254
+ type: Discord.ApplicationCommandOptionType.Subcommand,
255
+ name: "set",
256
+ description: "Change a setting",
257
+ options: [
258
+ ChatInputOptions.string({ name: "key", description: "Setting name", required: true }),
259
+ ChatInputOptions.string({ name: "value", description: "New value", required: true })
260
+ ]
261
+ }
262
+ ],
263
+ onExecute({ interaction }) {
264
+ const subcommand = interaction.options.getSubcommand();
265
+ // Handle based on subcommand
266
+ }
267
+ });
268
+ ```
269
+
270
+ ### Permissions
271
+
272
+ ```javascript
273
+ ChatInput({
274
+ name: "ban",
275
+ description: "Ban a user",
276
+ defaultMemberPermissions: ["BanMembers"], // Required permission
277
+ directMessages: false, // Disable in DMs
278
+ onExecute({ interaction }) { /* ... */ }
279
+ });
280
+ ```
281
+
282
+ ### Context Menus
283
+
284
+ ```javascript
285
+ // Message Context Menu (right-click on message)
286
+ dbi.register(({ MessageContextMenu }) => {
287
+ MessageContextMenu({
288
+ name: "Report Message",
289
+ async onExecute({ interaction }) {
290
+ const message = interaction.targetMessage;
291
+ await interaction.reply({ content: `Reported: ${message.id}`, ephemeral: true });
292
+ }
293
+ });
294
+ });
295
+
296
+ // User Context Menu (right-click on user)
297
+ dbi.register(({ UserContextMenu }) => {
298
+ UserContextMenu({
299
+ name: "View Profile",
300
+ async onExecute({ interaction }) {
301
+ const user = interaction.targetUser;
302
+ await interaction.reply({ content: `Profile: ${user.tag}`, ephemeral: true });
303
+ }
304
+ });
305
+ });
306
+ ```
307
+
308
+ ---
309
+
310
+ ## Components
311
+
312
+ ### Buttons
313
+
314
+ ```javascript
315
+ const Discord = require("discord.js");
316
+
317
+ dbi.register(({ ChatInput, Button }) => {
318
+ Button({
319
+ name: "action-btn",
320
+ options: {
321
+ style: Discord.ButtonStyle.Primary,
322
+ label: "Click Me",
323
+ emoji: "👋"
324
+ },
325
+ onExecute({ interaction, data }) {
326
+ const [action] = data; // Access referenced data
327
+ interaction.reply({ content: `Action: ${action}`, ephemeral: true });
328
+ }
329
+ });
330
+
331
+ ChatInput({
332
+ name: "actions",
333
+ description: "Show action buttons",
334
+ onExecute({ interaction, dbi }) {
335
+ const button = dbi.interaction("action-btn");
336
+
337
+ interaction.reply({
338
+ content: "Choose an action:",
339
+ components: [{
340
+ type: Discord.ComponentType.ActionRow,
341
+ components: [
342
+ button.toJSON({
343
+ overrides: { label: "Accept", style: Discord.ButtonStyle.Success },
344
+ reference: { data: ["accept"] }
345
+ }),
346
+ button.toJSON({
347
+ overrides: { label: "Decline", style: Discord.ButtonStyle.Danger },
348
+ reference: { data: ["decline"] }
349
+ })
350
+ ]
351
+ }]
352
+ });
353
+ }
354
+ });
355
+ });
356
+ ```
357
+
358
+ Button Styles: `Primary`, `Secondary`, `Success`, `Danger`, `Link`, `Premium`
359
+
360
+ ### Select Menus
361
+
362
+ ```javascript
363
+ dbi.register(({ StringSelectMenu }) => {
364
+ StringSelectMenu({
365
+ name: "color-select",
366
+ options: {
367
+ placeholder: "Choose a color...",
368
+ minValues: 1,
369
+ maxValues: 1,
370
+ options: [
371
+ { label: "Red", value: "red", emoji: "🔴", description: "A warm color" },
372
+ { label: "Green", value: "green", emoji: "🟢" },
373
+ { label: "Blue", value: "blue", emoji: "🔵" }
374
+ ]
375
+ },
376
+ onExecute({ interaction }) {
377
+ const selected = interaction.values[0];
378
+ interaction.reply(`You selected: ${selected}`);
379
+ }
380
+ });
381
+ });
382
+
383
+ // Other select menu types
384
+ UserSelectMenu({ /* ... */ }); // Select users
385
+ RoleSelectMenu({ /* ... */ }); // Select roles
386
+ ChannelSelectMenu({ /* ... */ }); // Select channels
387
+ MentionableSelectMenu({ /* ... */ }); // Select users or roles
388
+ ```
389
+
390
+ ### Modals
391
+
392
+ ```javascript
393
+ dbi.register(({ Modal, Button }) => {
394
+ Modal({
395
+ name: "feedback-modal",
396
+ options: {
397
+ title: "Send Feedback",
398
+ components: [
399
+ {
400
+ type: Discord.ComponentType.ActionRow,
401
+ components: [{
402
+ type: Discord.ComponentType.TextInput,
403
+ customId: "subject",
404
+ label: "Subject",
405
+ style: Discord.TextInputStyle.Short,
406
+ placeholder: "Brief description",
407
+ required: true,
408
+ minLength: 5,
409
+ maxLength: 100
410
+ }]
411
+ },
412
+ {
413
+ type: Discord.ComponentType.ActionRow,
414
+ components: [{
415
+ type: Discord.ComponentType.TextInput,
416
+ customId: "message",
417
+ label: "Message",
418
+ style: Discord.TextInputStyle.Paragraph,
419
+ placeholder: "Your detailed feedback...",
420
+ required: true
421
+ }]
422
+ }
423
+ ]
424
+ },
425
+ async onExecute({ interaction }) {
426
+ const subject = interaction.fields.getTextInputValue("subject");
427
+ const message = interaction.fields.getTextInputValue("message");
428
+ await interaction.reply({ content: "Thanks for your feedback!", ephemeral: true });
429
+ }
430
+ });
431
+
432
+ Button({
433
+ name: "open-feedback",
434
+ options: { style: Discord.ButtonStyle.Primary, label: "Feedback" },
435
+ async onExecute({ interaction, dbi }) {
436
+ const modal = dbi.interaction("feedback-modal").toJSON();
437
+ await interaction.showModal(modal);
438
+ }
439
+ });
440
+ });
441
+ ```
442
+
443
+ ### Reference System
444
+
445
+ Pass data through components without database:
446
+
447
+ ```javascript
448
+ // Primitive values are encoded in custom ID
449
+ button.toJSON({
450
+ reference: {
451
+ data: ["userId123", 42, true] // string, number, boolean
452
+ }
453
+ });
454
+
455
+ // Objects are stored in memory with auto-cleanup
456
+ button.toJSON({
457
+ reference: {
458
+ data: [{ complex: "object", nested: { data: true } }],
459
+ ttl: 300000 // Auto-expire in 5 minutes
460
+ }
461
+ });
462
+
463
+ // Access in handler
464
+ Button({
465
+ name: "my-btn",
466
+ onExecute({ data }) {
467
+ const [primitiveOrObject] = data;
468
+
469
+ // If object, has $ref and $unRef
470
+ if (primitiveOrObject?.$ref) {
471
+ console.log(primitiveOrObject.$ref); // Reference ID
472
+ primitiveOrObject.$unRef(); // Clean up when done
473
+ }
474
+ }
475
+ });
476
+ ```
477
+
478
+ ### Inline Components
479
+
480
+ Create one-time use components without pre-registration:
481
+
482
+ ```javascript
483
+ dbi.register(({ ChatInput, createInlineButton, createInlineStringSelectMenu }) => {
484
+ ChatInput({
485
+ name: "confirm",
486
+ description: "Confirm an action",
487
+ async onExecute({ interaction }) {
488
+ const confirmBtn = createInlineButton({
489
+ options: { style: Discord.ButtonStyle.Success, label: "Confirm" },
490
+ onExecute({ interaction }) {
491
+ interaction.reply("Confirmed!");
492
+ }
493
+ });
494
+
495
+ const cancelBtn = createInlineButton({
496
+ options: { style: Discord.ButtonStyle.Danger, label: "Cancel" },
497
+ onExecute({ interaction }) {
498
+ interaction.reply("Cancelled!");
499
+ }
500
+ });
501
+
502
+ await interaction.reply({
503
+ content: "Are you sure?",
504
+ components: [{
505
+ type: Discord.ComponentType.ActionRow,
506
+ components: [confirmBtn.toJSON(), cancelBtn.toJSON()]
507
+ }]
508
+ });
509
+ }
510
+ });
511
+ });
512
+ ```
513
+
514
+ Inline creators: `createInlineButton`, `createInlineStringSelectMenu`, `createInlineUserSelectMenu`, `createInlineRoleSelectMenu`, `createInlineChannelSelectMenu`, `createInlineMentionableSelectMenu`, `createInlineModal`, `createInlineEvent`
515
+
516
+ ---
517
+
518
+ ## Events
519
+
520
+ ### Basic Event Handler
521
+
522
+ ```javascript
523
+ dbi.register(({ Event }) => {
524
+ Event({
525
+ name: "clientReady",
526
+ id: "ready-logger", // Unique ID for multiple handlers of same event
527
+ onExecute({ client }) {
528
+ console.log(`Bot is online as ${client.user.tag}`);
529
+ }
530
+ });
531
+
532
+ Event({
533
+ name: "messageCreate",
534
+ id: "message-handler",
535
+ onExecute({ message }) {
536
+ if (message.author.bot) return;
537
+ console.log(`${message.author.tag}: ${message.content}`);
538
+ }
539
+ });
540
+
541
+ Event({
542
+ name: "guildMemberAdd",
543
+ id: "welcome",
544
+ async onExecute({ member }) {
545
+ const channel = member.guild.systemChannel;
546
+ if (channel) await channel.send(`Welcome ${member}!`);
547
+ }
548
+ });
549
+ });
550
+ ```
551
+
552
+ ### Common Events
553
+
554
+ | Event Name | Parameters |
555
+ |------------|------------|
556
+ | `clientReady` | `{ client }` |
557
+ | `messageCreate` | `{ message }` |
558
+ | `messageDelete` | `{ message }` |
559
+ | `messageUpdate` | `{ oldMessage, newMessage }` |
560
+ | `guildCreate` | `{ guild }` |
561
+ | `guildDelete` | `{ guild }` |
562
+ | `guildMemberAdd` | `{ member }` |
563
+ | `guildMemberRemove` | `{ member }` |
564
+ | `interactionCreate` | `{ interaction }` |
565
+ | `voiceStateUpdate` | `{ oldState, newState }` |
566
+
567
+ ### Custom Events
568
+
569
+ ```javascript
570
+ dbi.register(({ CustomEvent, Event }) => {
571
+ CustomEvent({
572
+ name: "userLevelUp",
573
+ map: { userId: "userId", newLevel: "newLevel", guild: "guild" }
574
+ });
575
+
576
+ Event({
577
+ name: "userLevelUp",
578
+ id: "levelup-announcer",
579
+ onExecute({ userId, newLevel, guild }) {
580
+ guild.systemChannel?.send(`🎉 <@${userId}> reached level ${newLevel}!`);
581
+ }
582
+ });
583
+ });
584
+
585
+ // Trigger from anywhere
586
+ dbi.emit("userLevelUp", { userId: "123", newLevel: 10, guild: someGuild });
587
+ ```
588
+
589
+ ### DBI Internal Events
590
+
591
+ ```javascript
592
+ dbi.events.on("beforeInteraction", async (ctx) => {
593
+ console.log(`Interaction: ${ctx.dbiInteraction.name}`);
594
+ return true; // Continue execution
595
+ });
596
+
597
+ dbi.events.on("afterInteraction", async (ctx) => {
598
+ console.log(`Completed: ${ctx.dbiInteraction.name}`);
599
+ return true;
600
+ });
601
+
602
+ dbi.events.on("interactionError", async ({ interaction, error }) => {
603
+ console.error("Error:", error);
604
+ await interaction.reply({ content: "An error occurred.", ephemeral: true });
605
+ return true;
606
+ });
607
+
608
+ dbi.events.on("interactionRateLimit", async ({ interaction, remainingTime }) => {
609
+ const seconds = Math.ceil(remainingTime / 1000);
610
+ await interaction.reply({ content: `Cooldown: ${seconds}s`, ephemeral: true });
611
+ return false; // Don't execute
612
+ });
613
+ ```
614
+
615
+ ---
616
+
617
+ ## Localization
618
+
619
+ ### Content Localization
620
+
621
+ ```javascript
622
+ dbi.register(({ Locale }) => {
623
+ Locale({
624
+ name: "en",
625
+ data: {
626
+ greeting: "Hello!",
627
+ welcome: "Welcome, {0}!",
628
+ levelUp: "{0} reached level {1}!",
629
+ commands: {
630
+ help: { title: "Help Menu", description: "Available commands:" }
631
+ }
632
+ }
633
+ });
634
+
635
+ Locale({
636
+ name: "tr",
637
+ data: {
638
+ greeting: "Merhaba!",
639
+ welcome: "Hoş geldin, {0}!",
640
+ levelUp: "{0} seviye {1}'e ulaştı!",
641
+ commands: {
642
+ help: { title: "Yardım Menüsü", description: "Mevcut komutlar:" }
643
+ }
644
+ }
645
+ });
646
+ });
647
+ ```
648
+
649
+ ### Using Locales
650
+
651
+ ```javascript
652
+ ChatInput({
653
+ name: "greet",
654
+ description: "Greet the user",
655
+ onExecute({ interaction, locale }) {
656
+ // User's locale (based on Discord client language)
657
+ const greeting = locale.user.data.greeting();
658
+ const welcome = locale.user.data.welcome(interaction.user.username);
659
+ const title = locale.user.data.commands.help.title();
660
+
661
+ // Guild's locale
662
+ const guildGreeting = locale.guild?.data.greeting?.();
663
+
664
+ interaction.reply(welcome);
665
+ }
666
+ });
667
+
668
+ // Access specific locale
669
+ const enLocale = dbi.locale("en");
670
+ const message = enLocale.data.levelUp("John", 10);
671
+ ```
672
+
673
+ ### Interaction Localization (Command Translations)
674
+
675
+ ```javascript
676
+ dbi.register(({ ChatInput, InteractionLocale }) => {
677
+ ChatInput({
678
+ name: "ayarlar", // Turkish default
679
+ description: "Bot ayarlarını değiştir",
680
+ onExecute({ interaction }) { /* ... */ }
681
+ });
682
+
683
+ InteractionLocale({
684
+ name: "ayarlar",
685
+ data: {
686
+ en: {
687
+ name: "settings",
688
+ description: "Change bot settings",
689
+ options: {
690
+ dil: {
691
+ name: "language",
692
+ description: "Preferred language"
693
+ }
694
+ }
695
+ },
696
+ es: {
697
+ name: "ajustes",
698
+ description: "Cambiar configuración del bot"
699
+ }
700
+ }
701
+ });
702
+ });
703
+ ```
704
+
705
+ ---
706
+
707
+ ## Svelte Components (HTMLComponentsV2)
708
+
709
+ Build reactive Discord UIs with Svelte 5:
710
+
711
+ ### Registration
712
+
713
+ ```javascript
714
+ const path = require("path");
715
+
716
+ dbi.register(({ HTMLComponentsV2, ChatInput }) => {
717
+ HTMLComponentsV2({
718
+ name: "counter",
719
+ mode: "svelte",
720
+ file: path.join(__dirname, "counter.svelte")
721
+ });
722
+
723
+ ChatInput({
724
+ name: "counter",
725
+ description: "Interactive counter",
726
+ async onExecute({ interaction, dbi }) {
727
+ const component = dbi.interaction("counter");
728
+ await component.send(interaction, {
729
+ data: { count: 0 }
730
+ });
731
+ }
732
+ });
733
+ });
734
+ ```
735
+
736
+ ### Svelte Component (counter.svelte)
737
+
738
+ ```svelte
739
+ <script>
740
+ /// <reference types="@mostfeatured/dbi/svelte" />
741
+
742
+ let { count = 0 } = $props();
743
+
744
+ function increment() {
745
+ data.count++;
746
+ }
747
+
748
+ function decrement() {
749
+ data.count--;
750
+ }
751
+
752
+ function reset(ctx) {
753
+ data.count = 0;
754
+ ctx.interaction.reply({ content: "Reset!", flags: ["Ephemeral"] });
755
+ }
756
+
757
+ onMount(() => {
758
+ const interval = setInterval(() => {
759
+ // Auto-updates component every second
760
+ }, 1000);
761
+ return () => clearInterval(interval); // Cleanup
762
+ });
763
+ </script>
764
+
765
+ <components>
766
+ <container accent-color="5865F2">
767
+ <components>
768
+ <text-display>## Counter: {count}</text-display>
769
+ <action-row>
770
+ <button style="Primary" handler={decrement}>-1</button>
771
+ <button style="Primary" handler={increment}>+1</button>
772
+ <button style="Danger" handler={reset}>Reset</button>
773
+ </action-row>
774
+ </components>
775
+ </container>
776
+ </components>
777
+ ```
778
+
779
+ ### Svelte HTML Elements
780
+
781
+ Layout:
782
+ - `<components>` - Root wrapper
783
+ - `<action-row>` - Container for buttons (max 5) or single select menu
784
+ - `<container accent-color="hex" spoiler>` - Colored container
785
+ - `<section>` - Section with components and accessory
786
+ - `<separator divider spacing="1-3">` - Visual divider
787
+
788
+ Interactive:
789
+ - `<button style="Primary|Secondary|Success|Danger|Link|Premium" handler={fn} emoji="🎉" disabled>Label</button>`
790
+ - `<string-select placeholder="..." min-values="1" max-values="3" handler={fn}>`
791
+ - `<option value="x" description="..." emoji="..." default>Label</option>`
792
+ - `<user-select>`, `<role-select>`, `<channel-select>`, `<mentionable-select>`
793
+
794
+ Display:
795
+ - `<text-display>Markdown content</text-display>`
796
+ - `<thumbnail url="...">` or `<thumbnail media="...">`
797
+ - `<media-gallery>` with `<item url="..." description="..." spoiler>`
798
+ - `<file url="attachment://file.pdf" spoiler>`
799
+
800
+ Modal:
801
+ - `<text-input id="..." label="..." placeholder="..." style="Short|Paragraph" min-length="1" max-length="100" required>Default</text-input>`
802
+
803
+ ### Svelte Globals
804
+
805
+ ```javascript
806
+ // Reactive data updates
807
+ data.property = newValue; // Triggers re-render
808
+
809
+ // Render control
810
+ render(); // Force immediate render
811
+ update(); // Use interaction.update()
812
+ rerender(); // Use message.edit()
813
+ noRender(); // Disable auto-render for this handler
814
+ setThrottle(ms); // Set min interval between renders
815
+
816
+ // Lifecycle
817
+ onMount(() => { return cleanup; });
818
+ onDestroy(() => { /* cleanup */ });
819
+ destroy(); // Manually destroy component
820
+ ```
821
+
822
+ ---
823
+
824
+ ## Rate Limiting
825
+
826
+ ### Declarative Rate Limits
827
+
828
+ ```javascript
829
+ ChatInput({
830
+ name: "daily",
831
+ description: "Daily reward",
832
+ rateLimits: [
833
+ { type: "User", duration: 86400000 } // 24 hours
834
+ ],
835
+ onExecute({ interaction }) {
836
+ interaction.reply("Here's your daily reward!");
837
+ }
838
+ });
839
+ ```
840
+
841
+ Rate Limit Types: `User`, `Channel`, `Guild`, `Member`, `Message`
842
+
843
+ ### Dynamic Rate Limits
844
+
845
+ ```javascript
846
+ ChatInput({
847
+ name: "action",
848
+ description: "Do something",
849
+ async onExecute({ interaction, setRateLimit }) {
850
+ const isPremium = await checkPremium(interaction.user.id);
851
+ await setRateLimit("User", isPremium ? 30000 : 300000);
852
+ interaction.reply("Done!");
853
+ }
854
+ });
855
+ ```
856
+
857
+ ---
858
+
859
+ ## Message Commands
860
+
861
+ Enable prefix-based commands that mirror slash commands:
862
+
863
+ ```javascript
864
+ const dbi = createDBI("my-bot", {
865
+ discord: { /* ... */ },
866
+ messageCommands: {
867
+ prefixes: ["!", ".", "?"],
868
+ // Or dynamic: async ({ message }) => [await getGuildPrefix(message.guild?.id)]
869
+ typeAliases: {
870
+ booleans: { "yes": true, "no": false, "on": true, "off": false }
871
+ }
872
+ },
873
+ defaults: {
874
+ messageCommands: {
875
+ deferReplyContent: "Processing..."
876
+ }
877
+ }
878
+ });
879
+ ```
880
+
881
+ Usage: `!ping`, `!greet @User Hello!`
882
+
883
+ ### Aliases and Rest Arguments
884
+
885
+ ```javascript
886
+ ChatInput({
887
+ name: "help",
888
+ description: "Show help",
889
+ other: {
890
+ messageCommand: {
891
+ aliases: ["h", "?", "commands"],
892
+ ignore: false // Set true to disable message command
893
+ }
894
+ },
895
+ onExecute({ interaction }) { /* ... */ }
896
+ });
897
+
898
+ // Rest string (captures all remaining text)
899
+ ChatInputOptions.string({
900
+ name: "message",
901
+ description: "The message",
902
+ required: true,
903
+ messageCommands: { rest: true }
904
+ })
905
+ ```
906
+
907
+ ---
908
+
909
+ ## Multi-Client Support
910
+
911
+ ```javascript
912
+ const dbi = createDBI("my-bot", {
913
+ discord: [
914
+ { namespace: "main", token: process.env.MAIN_TOKEN, options: { intents: ["Guilds"] } },
915
+ { namespace: "music", token: process.env.MUSIC_TOKEN, options: { intents: ["GuildVoiceStates"] } }
916
+ ]
917
+ });
918
+
919
+ // Access clients
920
+ const mainClient = dbi.client("main");
921
+ const musicClient = dbi.client("music");
922
+
923
+ // Publish to specific client
924
+ ChatInput({
925
+ name: "play",
926
+ description: "Play music",
927
+ publish: "music", // Only on music bot
928
+ onExecute({ clientNamespace }) { /* ... */ }
929
+ });
930
+ ```
931
+
932
+ ---
933
+
934
+ ## Sharding
935
+
936
+ ```javascript
937
+ // Default sharding
938
+ const dbi = createDBI("my-bot", { sharding: "default", /* ... */ });
939
+
940
+ // Hybrid sharding (discord-hybrid-sharding)
941
+ const dbi = createDBI("my-bot", { sharding: "hybrid", /* ... */ });
942
+
943
+ // Access cluster info
944
+ if (dbi.cluster) {
945
+ console.log(`Cluster: ${dbi.cluster.id}, Shards: ${dbi.cluster.shards}`);
946
+ }
947
+ ```
948
+
949
+ ---
950
+
951
+ ## Hot Reloading
952
+
953
+ ```javascript
954
+ dbi.register(({ ChatInput, Event, onUnload }) => {
955
+ let interval;
956
+
957
+ Event({
958
+ name: "clientReady",
959
+ id: "updater",
960
+ onExecute() {
961
+ interval = setInterval(() => { /* ... */ }, 60000);
962
+ }
963
+ });
964
+
965
+ onUnload(() => {
966
+ if (interval) clearInterval(interval);
967
+ console.log("Cleaned up!");
968
+ });
969
+ });
970
+
971
+ // Reload flow
972
+ await dbi.unload();
973
+ Utils.recursiveUnload("./src");
974
+ await Utils.recursiveImport("./src");
975
+ await dbi.load();
976
+ ```
977
+
978
+ ---
979
+
980
+ ## Flag-based Loading
981
+
982
+ ```javascript
983
+ ChatInput({
984
+ name: "debug-info",
985
+ description: "Debug information",
986
+ flag: "debug", // Only loaded with debug flag
987
+ onExecute({ interaction }) { /* ... */ }
988
+ });
989
+
990
+ // Load with specific flags
991
+ await dbi.load("debug");
992
+ await dbi.load("debug", "admin");
993
+ await dbi.load("all"); // Load everything
994
+ await dbi.load(); // Only non-flagged features
995
+ ```
996
+
997
+ ---
998
+
999
+ ## Data Management
1000
+
1001
+ ```javascript
1002
+ // Store/retrieve data
1003
+ dbi.set("config", { prefix: "!" });
1004
+ const config = dbi.get("config");
1005
+ dbi.has("config");
1006
+ dbi.delete("config");
1007
+
1008
+ // Access registered features
1009
+ const pingCmd = dbi.interaction("ping");
1010
+ const readyEvent = dbi.event("ready-handler");
1011
+ const enLocale = dbi.locale("en");
1012
+
1013
+ // Access collections
1014
+ dbi.data.interactions; // Discord.Collection
1015
+ dbi.data.events;
1016
+ dbi.data.locales;
1017
+ dbi.data.refs; // Reference storage
1018
+ ```
1019
+
1020
+ ---
1021
+
1022
+ ## Execution Context
1023
+
1024
+ All handlers receive a context object:
1025
+
1026
+ ```javascript
1027
+ onExecute({
1028
+ interaction, // Discord.js interaction
1029
+ dbi, // DBI instance
1030
+ dbiInteraction, // The registered interaction object
1031
+ locale, // { user: DBILocale, guild?: DBILocale }
1032
+ setRateLimit, // (type, duration) => Promise<void>
1033
+ other, // Custom shared data
1034
+ clientNamespace, // Multi-client namespace
1035
+ v2, // Components V2 enabled
1036
+ data // Referenced data array (components only)
1037
+ }) { /* ... */ }
1038
+ ```
1039
+
1040
+ ---
1041
+
1042
+ ## API Quick Reference
1043
+
1044
+ ### DBI Instance Methods
1045
+
1046
+ | Method | Description |
1047
+ |--------|-------------|
1048
+ | `register(callback)` | Register bot features |
1049
+ | `load(...flags)` | Load registered features |
1050
+ | `unload()` | Unload all features |
1051
+ | `login()` | Connect to Discord |
1052
+ | `publish(type, guildId?)` | Publish commands |
1053
+ | `interaction(name)` | Get registered interaction |
1054
+ | `event(name)` | Get registered event |
1055
+ | `locale(name)` | Get registered locale |
1056
+ | `client(namespace?)` | Get client |
1057
+ | `emit(name, args)` | Emit custom event |
1058
+ | `get/set/has/delete` | Data management |
1059
+
1060
+ ### Interaction Methods
1061
+
1062
+ | Method | Description |
1063
+ |--------|-------------|
1064
+ | `toJSON(args?)` | Get JSON for Discord API |
1065
+ | `createBuilder()` | Get fluent builder |
1066
+
1067
+ ### Component Builder Methods
1068
+
1069
+ | Method | Description |
1070
+ |--------|-------------|
1071
+ | `setLabel(label)` | Set button label |
1072
+ | `setEmoji(emoji)` | Set emoji |
1073
+ | `setStyle(style)` | Set style |
1074
+ | `setReference(data)` | Set reference data |
1075
+ | `setTTL(ms)` | Set time-to-live |
1076
+ | `toJSON()` | Build final JSON |
1077
+
1078
+ ---
1079
+
1080
+ ## License
1081
+
1082
+ GPL-3.0 License
1083
+
1084
+ ---
1085
+
1086
+ Made by TheArmagan and the MostFeatured team
1087
+ Package: @mostfeatured/dbi
1088
+ GitHub: https://github.com/MostFeatured/DiscordBotInfrastructure