1
1
import {
2
- ApplicationCommandType ,
3
2
AutocompleteInteraction ,
4
3
Awaitable ,
5
4
Collection ,
@@ -13,7 +12,11 @@ import {
13
12
import type { CommandKit } from '../../commandkit' ;
14
13
import { AsyncFunction , GenericFunction } from '../../context/async-context' ;
15
14
import { Logger } from '../../logger/Logger' ;
16
- import type { CommandData } from '../../types' ;
15
+ import type {
16
+ CommandData ,
17
+ CommandMetadata ,
18
+ CommandMetadataFunction ,
19
+ } from '../../types' ;
17
20
import colors from '../../utils/colors' ;
18
21
import { COMMANDKIT_IS_DEV } from '../../utils/constants' ;
19
22
import { CommandKitErrorCodes , isErrorType } from '../../utils/error-codes' ;
@@ -25,6 +28,14 @@ import { MessageCommandParser } from '../commands/MessageCommandParser';
25
28
import { CommandRegistrar } from '../register/CommandRegistrar' ;
26
29
import { Command , Middleware } from '../router' ;
27
30
import { getConfig } from '../../config/config' ;
31
+ import { beforeExecute , middlewareId } from '../middlewares/permissions' ;
32
+
33
+ const KNOWN_NON_HANDLER_KEYS = [
34
+ 'command' ,
35
+ 'generateMetadata' ,
36
+ 'metadata' ,
37
+ 'aiConfig' ,
38
+ ] ;
28
39
29
40
/**
30
41
* Function type for wrapping command execution with custom logic.
@@ -38,6 +49,8 @@ export type RunCommand = <T extends AsyncFunction>(fn: T) => T;
38
49
*/
39
50
export interface AppCommandNative {
40
51
command : CommandData | Record < string , any > ;
52
+ generateMetadata ?: CommandMetadataFunction ;
53
+ metadata ?: CommandMetadata ;
41
54
chatInput ?: ( ctx : Context ) => Awaitable < unknown > ;
42
55
autocomplete ?: ( ctx : Context ) => Awaitable < unknown > ;
43
56
message ?: ( ctx : Context ) => Awaitable < unknown > ;
@@ -73,8 +86,8 @@ interface AppCommandMiddleware {
73
86
*/
74
87
export interface LoadedCommand {
75
88
command : Command ;
89
+ metadata : CommandMetadata ;
76
90
data : AppCommand ;
77
- guilds ?: string [ ] ;
78
91
}
79
92
80
93
/**
@@ -129,8 +142,22 @@ const commandDataSchema = {
129
142
userContextMenu : ( c : unknown ) => typeof c === 'function' ,
130
143
} ;
131
144
145
+ /**
146
+ * @private
147
+ * @internal
148
+ */
132
149
export type CommandDataSchema = typeof commandDataSchema ;
150
+
151
+ /**
152
+ * @private
153
+ * @internal
154
+ */
133
155
export type CommandDataSchemaKey = keyof CommandDataSchema ;
156
+
157
+ /**
158
+ * @private
159
+ * @internal
160
+ */
134
161
export type CommandDataSchemaValue = CommandDataSchema [ CommandDataSchemaKey ] ;
135
162
136
163
/**
@@ -444,8 +471,8 @@ export class AppCommandHandler {
444
471
445
472
if (
446
473
source . guildId &&
447
- loadedCommand . guilds ?. length &&
448
- ! loadedCommand . guilds . includes ( source . guildId ! )
474
+ loadedCommand . metadata ?. guilds ?. length &&
475
+ ! loadedCommand . metadata ?. guilds . includes ( source . guildId ! )
449
476
) {
450
477
return null ;
451
478
}
@@ -499,8 +526,8 @@ export class AppCommandHandler {
499
526
( source instanceof CommandInteraction ||
500
527
source instanceof AutocompleteInteraction ) &&
501
528
source . guildId &&
502
- loadedCommand . guilds ?. length &&
503
- ! loadedCommand . guilds . includes ( source . guildId )
529
+ loadedCommand . metadata ?. guilds ?. length &&
530
+ ! loadedCommand . metadata ?. guilds . includes ( source . guildId )
504
531
) {
505
532
return null ;
506
533
}
@@ -516,6 +543,24 @@ export class AppCommandHandler {
516
543
}
517
544
}
518
545
546
+ if ( ! getConfig ( ) . disablePermissionsMiddleware ) {
547
+ middlewares . push ( {
548
+ data : {
549
+ // @ts -ignore
550
+ beforeExecute,
551
+ } ,
552
+ middleware : {
553
+ command : null ,
554
+ global : true ,
555
+ id : middlewareId ,
556
+ name : 'permissions' ,
557
+ parentPath : '' ,
558
+ path : '' ,
559
+ relativePath : '' ,
560
+ } ,
561
+ } ) ;
562
+ }
563
+
519
564
// No middleware for subcommands since they inherit from parent command
520
565
return {
521
566
command : loadedCommand ,
@@ -536,7 +581,7 @@ export class AppCommandHandler {
536
581
}
537
582
538
583
// Check aliases for prefix commands
539
- const aliases = loadedCommand . data . command . aliases ;
584
+ const aliases = loadedCommand . data . metadata ? .aliases ;
540
585
if ( aliases && Array . isArray ( aliases ) && aliases . includes ( name ) ) {
541
586
return loadedCommand ;
542
587
}
@@ -640,7 +685,7 @@ export class AppCommandHandler {
640
685
( v ) => v . data . command . name ,
641
686
) ;
642
687
const aliases = Array . from ( this . loadedCommands . values ( ) ) . flatMap (
643
- ( v ) => v . data . command . aliases || [ ] ,
688
+ ( v ) => v . metadata . aliases || [ ] ,
644
689
) ;
645
690
646
691
const allNames = [ ...commandNames , ...aliases ] ;
@@ -698,6 +743,12 @@ export class AppCommandHandler {
698
743
if ( command . path === null ) {
699
744
this . loadedCommands . set ( id , {
700
745
command,
746
+ metadata : {
747
+ guilds : [ ] ,
748
+ aliases : [ ] ,
749
+ userPermissions : [ ] ,
750
+ botPermissions : [ ] ,
751
+ } ,
701
752
data : {
702
753
command : {
703
754
name : command . name ,
@@ -719,6 +770,22 @@ export class AppCommandHandler {
719
770
) ;
720
771
}
721
772
773
+ const metadataFunc = commandFileData . generateMetadata ;
774
+ const metadataObj = commandFileData . metadata ;
775
+
776
+ if ( metadataFunc && metadataObj ) {
777
+ throw new Error (
778
+ 'A command may only export either `generateMetadata` or `metadata`, not both' ,
779
+ ) ;
780
+ }
781
+
782
+ const metadata = ( metadataFunc ? await metadataFunc ( ) : metadataObj ) ?? {
783
+ aliases : [ ] ,
784
+ guilds : [ ] ,
785
+ userPermissions : [ ] ,
786
+ botPermissions : [ ] ,
787
+ } ;
788
+
722
789
// Apply the specified logic for name and description
723
790
const commandName = commandFileData . command . name || command . name ;
724
791
const commandDescription =
@@ -729,7 +796,6 @@ export class AppCommandHandler {
729
796
...commandFileData . command ,
730
797
name : commandName ,
731
798
description : commandDescription ,
732
- aliases : commandFileData . command . aliases ,
733
799
} as CommandData ;
734
800
735
801
let handlerCount = 0 ;
@@ -747,7 +813,7 @@ export class AppCommandHandler {
747
813
) ;
748
814
}
749
815
750
- if ( key !== 'command' ) {
816
+ if ( ! KNOWN_NON_HANDLER_KEYS . includes ( key ) ) {
751
817
// command file includes a handler function (chatInput, message, etc)
752
818
handlerCount ++ ;
753
819
}
@@ -770,19 +836,53 @@ export class AppCommandHandler {
770
836
}
771
837
} ) ;
772
838
839
+ const commandJson =
840
+ 'toJSON' in lastUpdated && typeof lastUpdated . toJSON === 'function'
841
+ ? lastUpdated . toJSON ( )
842
+ : lastUpdated ;
843
+
844
+ if ( 'guilds' in commandJson || 'aliases' in commandJson ) {
845
+ Logger . warn (
846
+ `Command \`${ command . name } \` uses deprecated metadata properties. Please update to use the new \`metadata\` object or \`generateMetadata\` function.` ,
847
+ ) ;
848
+ }
849
+
773
850
this . loadedCommands . set ( id , {
774
851
command,
775
- guilds : commandFileData . command . guilds ,
852
+ metadata : {
853
+ guilds : commandJson . guilds ,
854
+ aliases : commandJson . aliases ,
855
+ ...metadata ,
856
+ } ,
776
857
data : {
777
858
...commandFileData ,
778
- command :
779
- 'toJSON' in lastUpdated && typeof lastUpdated . toJSON === 'function'
780
- ? lastUpdated . toJSON ( )
781
- : lastUpdated ,
859
+ metadata : {
860
+ guilds : commandJson . guilds ,
861
+ aliases : commandJson . aliases ,
862
+ ...metadata ,
863
+ } ,
864
+ command : commandJson ,
782
865
} ,
783
866
} ) ;
784
867
} catch ( error ) {
785
868
Logger . error ( `Failed to load command ${ command . name } (${ id } )` , error ) ;
786
869
}
787
870
}
871
+
872
+ /**
873
+ * Gets the metadata for a command.
874
+ * @param command - The command name to get metadata for
875
+ * @returns The command metadata or null if not found
876
+ */
877
+ public getMetadataFor ( command : string ) : CommandMetadata | null {
878
+ const loadedCommand = this . findCommandByName ( command ) ;
879
+ if ( ! loadedCommand ) return null ;
880
+
881
+ return ( loadedCommand . metadata ??= {
882
+ aliases : [ ] ,
883
+ guilds : [ ] ,
884
+ userPermissions : [ ] ,
885
+ botPermissions : [ ] ,
886
+ } ) ;
887
+ }
788
888
}
0 commit comments