spacecommands 1.0.0

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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +519 -0
  3. package/dist/Command.js +384 -0
  4. package/dist/CommandHandler.js +339 -0
  5. package/dist/FeatureHandler.js +89 -0
  6. package/dist/SlashCommands.js +220 -0
  7. package/dist/command-checks/channel-specific.js +30 -0
  8. package/dist/command-checks/guild-only-check.js +24 -0
  9. package/dist/command-checks/has-entitlement.js +52 -0
  10. package/dist/command-checks/has-permissions.js +39 -0
  11. package/dist/command-checks/has-roles.js +69 -0
  12. package/dist/command-checks/has-valid-arguments.js +54 -0
  13. package/dist/command-checks/in-cooldown.js +42 -0
  14. package/dist/command-checks/is-enabled.js +31 -0
  15. package/dist/command-checks/is-not-test-only.js +8 -0
  16. package/dist/command-checks/owner-only-check.js +22 -0
  17. package/dist/commands/channelonly.js +88 -0
  18. package/dist/commands/command.js +87 -0
  19. package/dist/commands/help/!ReactionListener.js +217 -0
  20. package/dist/commands/help/!get-first-embed.js +57 -0
  21. package/dist/commands/help/help.js +97 -0
  22. package/dist/commands/language.js +52 -0
  23. package/dist/commands/prefix.js +42 -0
  24. package/dist/commands/requiredrole.js +61 -0
  25. package/dist/commands/slash.js +102 -0
  26. package/dist/enums/CommandErrors.js +12 -0
  27. package/dist/enums/Events.js +9 -0
  28. package/dist/features/message-upsert.js +15 -0
  29. package/dist/get-all-files.js +25 -0
  30. package/dist/handlers/AutoModHandler.js +316 -0
  31. package/dist/handlers/ComponentHandler.js +110 -0
  32. package/dist/handlers/ContextMenuHandler.js +113 -0
  33. package/dist/handlers/EntitlementHandler.js +193 -0
  34. package/dist/handlers/ModalHandler.js +71 -0
  35. package/dist/handlers/PollHandler.js +230 -0
  36. package/dist/index.js +339 -0
  37. package/dist/message-handler.js +118 -0
  38. package/dist/models/channel-commands.js +49 -0
  39. package/dist/models/cooldown.js +51 -0
  40. package/dist/models/disabled-commands.js +45 -0
  41. package/dist/models/languages.js +46 -0
  42. package/dist/models/prefixes.js +46 -0
  43. package/dist/models/required-roles.js +49 -0
  44. package/dist/mongo.js +25 -0
  45. package/dist/permissions.js +39 -0
  46. package/dist/utils/ComponentBuilder.js +144 -0
  47. package/dist/utils/InteractionCollector.js +80 -0
  48. package/messages.json +391 -0
  49. package/package.json +72 -0
  50. package/typings.d.ts +276 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 SpaceCommands Contributors
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,519 @@
1
+ # SpaceCommands
2
+
3
+ SpaceCommands is a modern, feature-rich Discord.js command handler library. Built on Discord.js v14, it provides an easy-to-use framework for creating Discord bots with slash commands, permissions, cooldowns, and more.
4
+
5
+ ## Features
6
+
7
+ - ✨ **Modern Discord.js v14** - Built for the latest Discord features
8
+ - 🎯 **Slash Commands** - Full support for Discord's slash commands with autocomplete
9
+ - 📝 **Prefix Commands** - Traditional message-based commands
10
+ - 🔒 **Permission System** - Role and permission-based command restrictions
11
+ - ⏱️ **Cooldown System** - Per-user and global cooldowns with MongoDB persistence
12
+ - 🌍 **Multi-Language Support** - Built-in internationalization
13
+ - 🎨 **Category System** - Organize commands with custom categories
14
+ - 🗄️ **MongoDB Integration** - Optional database support for persistence
15
+ - 📦 **TypeScript Support** - Full TypeScript support with type definitions
16
+ - 🎮 **Interactive Components** - Buttons, select menus, and modals
17
+ - 📋 **Context Menus** - User and message context menu commands
18
+ - 💎 **Premium Features** - Discord entitlement and monetization support
19
+ - 🛠️ **Component Utilities** - Simplified builders and interaction collectors
20
+ - 📊 **Poll Support** - Native Discord polls with result tracking
21
+ - 🛡️ **AutoMod Integration** - Full AutoMod rule creation and management
22
+
23
+ ## Installation
24
+
25
+ **NPM**
26
+
27
+ ```bash
28
+ npm install spacecommands
29
+ ```
30
+
31
+ **Yarn**
32
+
33
+ ```bash
34
+ yarn add spacecommands
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ ```javascript
40
+ const { Client, IntentsBitField } = require('discord.js');
41
+ const SpaceCommands = require('spacecommands');
42
+ const path = require('path');
43
+
44
+ const client = new Client({
45
+ intents: [
46
+ IntentsBitField.Flags.Guilds,
47
+ IntentsBitField.Flags.GuildMessages,
48
+ IntentsBitField.Flags.MessageContent,
49
+ ],
50
+ });
51
+
52
+ client.on('ready', () => {
53
+ new SpaceCommands(client, {
54
+ commandsDir: path.join(__dirname, 'commands'),
55
+ featuresDir: path.join(__dirname, 'features'),
56
+ testServers: ['YOUR_TEST_SERVER_ID'],
57
+ botOwners: ['YOUR_USER_ID'],
58
+ mongoUri: process.env.MONGO_URI, // Optional
59
+ });
60
+ });
61
+
62
+ client.login(process.env.BOT_TOKEN);
63
+ ```
64
+
65
+ ## Creating Commands
66
+
67
+ ### Slash Command Example
68
+
69
+ ```javascript
70
+ module.exports = {
71
+ category: 'Utility',
72
+ description: 'Ping command',
73
+
74
+ slash: true, // or 'both' for slash and prefix
75
+
76
+ callback: ({ interaction }) => {
77
+ return 'Pong!';
78
+ },
79
+ };
80
+ ```
81
+
82
+ ### Prefix Command Example
83
+
84
+ ```javascript
85
+ module.exports = {
86
+ category: 'Utility',
87
+ description: 'Ping command',
88
+
89
+ aliases: ['pong'],
90
+
91
+ callback: ({ message }) => {
92
+ return 'Pong!';
93
+ },
94
+ };
95
+ ```
96
+
97
+ ## Configuration Options
98
+
99
+ | Option | Type | Description | Default |
100
+ |--------|------|-------------|---------|
101
+ | `commandsDir` | string | Absolute path to commands directory | Required |
102
+ | `featuresDir` | string | Absolute path to features directory | Optional |
103
+ | `mongoUri` | string | MongoDB connection URI | Optional |
104
+ | `testServers` | string[] | Guild IDs for testing commands | [] |
105
+ | `botOwners` | string[] | User IDs of bot owners | [] |
106
+ | `defaultLanguage` | string | Default language for messages | 'english' |
107
+ | `ephemeral` | boolean | Slash commands reply ephemerally | true |
108
+ | `showWarns` | boolean | Show warning messages | true |
109
+ | `typeScript` | boolean | Enable TypeScript support | false |
110
+
111
+ ## Command Options
112
+
113
+ ### Basic Options
114
+ - `category` - Command category for organization
115
+ - `description` - Command description (required for slash commands)
116
+ - `aliases` / `names` - Alternative command names
117
+ - `slash` - Enable as slash command (true, false, or 'both')
118
+
119
+ ### Permissions & Access
120
+ - `permissions` / `requiredPermissions` - Required Discord permissions
121
+ - `requireRoles` - Require specific roles
122
+ - `ownerOnly` - Restrict to bot owners only
123
+ - `guildOnly` - Disable in DMs
124
+ - `testOnly` - Only available in test servers
125
+
126
+ ### Arguments
127
+ - `minArgs` - Minimum required arguments
128
+ - `maxArgs` - Maximum allowed arguments
129
+ - `expectedArgs` - Argument format string
130
+ - `syntaxError` - Custom error messages per language
131
+
132
+ ### Advanced
133
+ - `cooldown` - Per-user cooldown (e.g., "5s", "1m")
134
+ - `globalCooldown` - Global cooldown (minimum 1m)
135
+ - `hidden` - Hide from help command
136
+ - `options` - Slash command options array
137
+
138
+ ## Interactive Components
139
+
140
+ SpaceCommands provides full support for Discord's interactive components including buttons, select menus, and modals.
141
+
142
+ ### Button Handlers
143
+
144
+ Register button handlers to respond to button clicks:
145
+
146
+ ```javascript
147
+ // In your bot initialization
148
+ const instance = new SpaceCommands(client, { ... });
149
+
150
+ // Register a button handler
151
+ instance.componentHandler.registerButtonHandler({
152
+ customId: 'my-button',
153
+ callback: async (interaction, instance) => {
154
+ await interaction.reply('Button clicked!');
155
+ },
156
+ });
157
+
158
+ // Use regex for dynamic button IDs
159
+ instance.componentHandler.registerButtonHandler({
160
+ customId: /^page-\d+$/,
161
+ callback: async (interaction, instance) => {
162
+ const pageNum = interaction.customId.split('-')[1];
163
+ await interaction.reply(`Showing page ${pageNum}`);
164
+ },
165
+ });
166
+ ```
167
+
168
+ ### Select Menu Handlers
169
+
170
+ Handle all types of select menus (string, user, role, channel, mentionable):
171
+
172
+ ```javascript
173
+ instance.componentHandler.registerSelectMenuHandler({
174
+ customId: 'role-select',
175
+ callback: async (interaction, instance) => {
176
+ const selectedRoles = interaction.values;
177
+ await interaction.reply(`Selected: ${selectedRoles.join(', ')}`);
178
+ },
179
+ });
180
+ ```
181
+
182
+ ### Component Builders
183
+
184
+ Use the simplified component builder utilities:
185
+
186
+ ```javascript
187
+ const { ComponentUtils } = require('spacecommands');
188
+
189
+ // Create a button
190
+ const button = ComponentUtils.createButton(
191
+ 'my-button',
192
+ 'Click Me',
193
+ ButtonStyle.Primary,
194
+ { emoji: '👋' }
195
+ );
196
+
197
+ // Create a select menu
198
+ const select = ComponentUtils.createStringSelect(
199
+ 'my-select',
200
+ 'Choose an option',
201
+ [
202
+ { label: 'Option 1', value: 'opt1' },
203
+ { label: 'Option 2', value: 'opt2' },
204
+ ]
205
+ );
206
+
207
+ // Create an action row
208
+ const row = ComponentUtils.createActionRow(button);
209
+ ```
210
+
211
+ ## Modals
212
+
213
+ Create and handle modal forms for user input:
214
+
215
+ ```javascript
216
+ const { ComponentUtils } = require('spacecommands');
217
+ const { TextInputStyle } = require('discord.js');
218
+
219
+ // Create a modal
220
+ const modal = ComponentUtils.createModal(
221
+ 'feedback-modal',
222
+ 'Submit Feedback',
223
+ ComponentUtils.createTextInputRow(
224
+ 'feedback-text',
225
+ 'Your Feedback',
226
+ TextInputStyle.Paragraph,
227
+ { placeholder: 'Tell us what you think...' }
228
+ )
229
+ );
230
+
231
+ // Show the modal
232
+ await interaction.showModal(modal);
233
+
234
+ // Register a modal handler
235
+ instance.modalHandler.registerModalHandler({
236
+ customId: 'feedback-modal',
237
+ callback: async (interaction, instance) => {
238
+ const feedback = interaction.fields.getTextInputValue('feedback-text');
239
+ await interaction.reply(`Thanks for your feedback: ${feedback}`);
240
+ },
241
+ });
242
+ ```
243
+
244
+ ## Context Menu Commands
245
+
246
+ Add user and message context menu commands (right-click menus):
247
+
248
+ ```javascript
249
+ instance.contextMenuHandler.registerContextMenu({
250
+ name: 'Get User Info',
251
+ type: ApplicationCommandType.User,
252
+ callback: async (interaction, instance) => {
253
+ const user = interaction.targetUser;
254
+ await interaction.reply(`User: ${user.tag}`);
255
+ },
256
+ });
257
+
258
+ instance.contextMenuHandler.registerContextMenu({
259
+ name: 'Quote Message',
260
+ type: ApplicationCommandType.Message,
261
+ callback: async (interaction, instance) => {
262
+ const message = interaction.targetMessage;
263
+ await interaction.reply(`"${message.content}" - ${message.author.tag}`);
264
+ },
265
+ });
266
+ ```
267
+
268
+ ## Autocomplete
269
+
270
+ Add autocomplete suggestions to slash command options:
271
+
272
+ ```javascript
273
+ instance.slashCommands.registerAutocomplete('search', async (interaction) => {
274
+ const focusedValue = interaction.options.getFocused();
275
+ const choices = ['apple', 'banana', 'cherry', 'date'];
276
+
277
+ const filtered = choices.filter(choice =>
278
+ choice.startsWith(focusedValue.toLowerCase())
279
+ );
280
+
281
+ await interaction.respond(
282
+ filtered.map(choice => ({ name: choice, value: choice }))
283
+ );
284
+ });
285
+ ```
286
+
287
+ ## Premium Features
288
+
289
+ Monetize your bot with Discord's entitlement system:
290
+
291
+ ### Register SKUs
292
+
293
+ ```javascript
294
+ instance.entitlementHandler.registerSKU({
295
+ skuId: '1234567890',
296
+ name: 'Premium Tier',
297
+ description: 'Access to premium features',
298
+ });
299
+ ```
300
+
301
+ ### Premium-Only Commands
302
+
303
+ ```javascript
304
+ module.exports = {
305
+ category: 'Premium',
306
+ description: 'Premium-only command',
307
+
308
+ // Require specific entitlement
309
+ requiredEntitlements: ['1234567890'],
310
+
311
+ // OR require any active entitlement
312
+ premiumOnly: true,
313
+
314
+ callback: ({ interaction }) => {
315
+ return 'Welcome, premium user!';
316
+ },
317
+ };
318
+ ```
319
+
320
+ ### Check Entitlements Programmatically
321
+
322
+ ```javascript
323
+ const { hasEntitlement } = await instance.entitlementHandler.hasEntitlement(
324
+ user.id,
325
+ 'sku-id'
326
+ );
327
+
328
+ if (hasEntitlement) {
329
+ // Grant premium features
330
+ }
331
+ ```
332
+
333
+ ## Interaction Collectors
334
+
335
+ Easily collect component interactions:
336
+
337
+ ```javascript
338
+ const { InteractionCollectorUtils } = require('spacecommands');
339
+
340
+ // Await a button click
341
+ const button = await InteractionCollectorUtils.awaitButton(
342
+ message,
343
+ (i) => i.user.id === interaction.user.id,
344
+ 30000 // 30 second timeout
345
+ );
346
+
347
+ if (button) {
348
+ await button.reply('Button clicked!');
349
+ }
350
+
351
+ // Create a select menu collector
352
+ const collector = InteractionCollectorUtils.createSelectMenuCollector(
353
+ message,
354
+ (i) => i.user.id === interaction.user.id,
355
+ { time: 60000 }
356
+ );
357
+
358
+ collector.on('collect', async (i) => {
359
+ await i.reply(`Selected: ${i.values.join(', ')}`);
360
+ });
361
+ ```
362
+
363
+ ## Polls
364
+
365
+ Create and manage Discord's native polls:
366
+
367
+ ```javascript
368
+ // Access the poll handler
369
+ const pollHandler = instance.pollHandler;
370
+
371
+ // Get a poll from a message
372
+ const poll = message.poll;
373
+
374
+ if (poll) {
375
+ // Get poll results
376
+ const results = await pollHandler.getPollResults(poll);
377
+
378
+ // Get winning answer(s)
379
+ const winners = pollHandler.getWinningAnswers(poll);
380
+ console.log(`Winning answer: ${winners[0].text}`);
381
+
382
+ // Get poll statistics
383
+ const stats = pollHandler.getPollStats(poll);
384
+ console.log(`Total votes: ${stats.totalVotes}`);
385
+
386
+ // Get formatted results
387
+ const formatted = await pollHandler.getFormattedResults(poll);
388
+ await message.channel.send(formatted);
389
+
390
+ // Check if a user voted
391
+ const hasVoted = await pollHandler.hasUserVoted(poll, userId);
392
+
393
+ // Get user's votes
394
+ const userVotes = await pollHandler.getUserVotes(poll, userId);
395
+
396
+ // End poll early
397
+ await pollHandler.endPoll(poll);
398
+ }
399
+
400
+ // Register handler for when a poll ends
401
+ pollHandler.registerPollEndHandler({
402
+ pollId: /poll-.+/, // Regex or specific message ID
403
+ callback: async (poll, instance) => {
404
+ const results = await instance.pollHandler.getFormattedResults(poll);
405
+ await poll.message.channel.send(`Poll ended!\n${results}`);
406
+ },
407
+ });
408
+
409
+ // Fetch a poll from a message ID
410
+ const fetchedPoll = await pollHandler.fetchPoll(messageId, channelId);
411
+ ```
412
+
413
+ ## AutoMod
414
+
415
+ Manage Discord's AutoMod rules programmatically:
416
+
417
+ ```javascript
418
+ const { AutoModerationRuleEventType, AutoModerationActionType } = require('discord.js');
419
+
420
+ // Access the AutoMod handler
421
+ const autoModHandler = instance.autoModHandler;
422
+
423
+ // Create a keyword filter rule
424
+ const keywordRule = await autoModHandler.createKeywordRule(
425
+ guild,
426
+ 'No Profanity',
427
+ ['badword1', 'badword2'],
428
+ [
429
+ {
430
+ type: AutoModerationActionType.BlockMessage,
431
+ metadata: { customMessage: 'Please keep chat family-friendly!' }
432
+ },
433
+ {
434
+ type: AutoModerationActionType.Timeout,
435
+ metadata: { durationSeconds: 60 }
436
+ }
437
+ ],
438
+ {
439
+ allowList: ['allowed-phrase'],
440
+ exemptRoles: ['moderator-role-id'],
441
+ exemptChannels: ['staff-channel-id']
442
+ }
443
+ );
444
+
445
+ // Create a spam rule
446
+ const spamRule = await autoModHandler.createSpamRule(
447
+ guild,
448
+ 'Anti-Spam',
449
+ [{ type: AutoModerationActionType.BlockMessage }]
450
+ );
451
+
452
+ // Create a mention spam rule
453
+ const mentionRule = await autoModHandler.createMentionSpamRule(
454
+ guild,
455
+ 'Mention Limit',
456
+ 5, // Maximum 5 mentions
457
+ [{ type: AutoModerationActionType.BlockMessage }],
458
+ { raidProtection: true }
459
+ );
460
+
461
+ // Create a regex pattern rule
462
+ const regexRule = await autoModHandler.createRegexRule(
463
+ guild,
464
+ 'Link Blocker',
465
+ ['(https?://)?([\\da-z\\.-]+)\\.([a-z\\.]{2,6})'],
466
+ [{ type: AutoModerationActionType.BlockMessage }]
467
+ );
468
+
469
+ // Create a preset keyword rule
470
+ const { AutoModerationRuleKeywordPresetType } = require('discord.js');
471
+ const presetRule = await autoModHandler.createPresetRule(
472
+ guild,
473
+ 'Block Profanity',
474
+ [AutoModerationRuleKeywordPresetType.Profanity],
475
+ [{ type: AutoModerationActionType.BlockMessage }]
476
+ );
477
+
478
+ // Register handler for AutoMod actions
479
+ autoModHandler.registerActionHandler({
480
+ ruleId: 'specific-rule-id', // Optional: specific rule or regex
481
+ callback: async (execution, instance) => {
482
+ console.log(`AutoMod triggered by ${execution.userId}`);
483
+ console.log(`Rule: ${execution.ruleId}`);
484
+ console.log(`Action: ${execution.action.type}`);
485
+
486
+ // Log to a channel
487
+ const logChannel = execution.guild.channels.cache.get('log-channel-id');
488
+ if (logChannel) {
489
+ await logChannel.send(`AutoMod: User <@${execution.userId}> triggered rule ${execution.ruleTriggerType}`);
490
+ }
491
+ },
492
+ });
493
+
494
+ // Fetch all AutoMod rules for a guild
495
+ const rules = await autoModHandler.fetchGuildRules(guild);
496
+
497
+ // Update an existing rule
498
+ await autoModHandler.updateRule(guild, ruleId, {
499
+ enabled: false, // Disable the rule
500
+ });
501
+
502
+ // Delete a rule
503
+ await autoModHandler.deleteRule(guild, ruleId);
504
+
505
+ // Clear cache
506
+ autoModHandler.clearGuildCache(guildId);
507
+ ```
508
+
509
+ ## Documentation
510
+
511
+ For detailed documentation, examples, and guides, visit our [GitHub repository](https://github.com/VicToMeyeZR/SpaceCommands).
512
+
513
+ ## Support
514
+
515
+ If you need help or have questions, please open an issue on our [GitHub repository](https://github.com/VicToMeyeZR/SpaceCommands/issues).
516
+
517
+ ## License
518
+
519
+ MIT License - see LICENSE file for details.