@@ -75,90 +75,113 @@ export class AppCommandRunner {
7575 env . variables . set ( 'execHandlerKind' , executionMode ) ;
7676 env . variables . set ( 'customHandler' , options ?. handler ?? null ) ;
7777
78- const middlewareCtx = new MiddlewareContext ( commandkit , {
79- command : prepared . command ,
80- environment : env ,
81- executionMode,
82- interaction : ! ( source instanceof Message )
83- ? ( source as ChatInputCommandInteraction )
84- : ( null as never ) ,
85- message : source instanceof Message ? source : ( null as never ) ,
86- forwarded : false ,
87- customArgs : {
88- setCommandRunner : ( fn : RunCommand ) => {
89- runCommand = fn ;
78+ try {
79+ const middlewareCtx = new MiddlewareContext ( commandkit , {
80+ command : prepared . command ,
81+ environment : env ,
82+ executionMode,
83+ interaction : ! ( source instanceof Message )
84+ ? ( source as ChatInputCommandInteraction )
85+ : ( null as never ) ,
86+ message : source instanceof Message ? source : ( null as never ) ,
87+ forwarded : false ,
88+ customArgs : {
89+ setCommandRunner : ( fn : RunCommand ) => {
90+ runCommand = fn ;
91+ } ,
9092 } ,
91- } ,
92- messageCommandParser : prepared . messageCommandParser ,
93- } ) ;
94-
95- const beforeMiddlewares = prepared . middlewares . filter (
96- ( m ) => m . data . beforeExecute ,
97- ) ;
98-
99- let beforeMiddlewaresStopped = false ;
93+ messageCommandParser : prepared . messageCommandParser ,
94+ } ) ;
10095
101- // Run middleware before command execution
102- if ( beforeMiddlewares . length ) {
103- await provideContext ( env , async ( ) => {
104- for ( const middleware of beforeMiddlewares ) {
105- try {
106- await middleware . data . beforeExecute ( middlewareCtx ) ;
107- } catch ( e ) {
108- if ( isErrorType ( e , CommandKitErrorCodes . StopMiddlewares ) ) {
109- beforeMiddlewaresStopped = true ;
110- Logger . debug (
111- `Middleware propagation stopped for command "${ middlewareCtx . commandName } ". stopMiddlewares() was called inside a beforeExecute function at "${ middleware . middleware . relativePath } "` ,
112- ) ;
113- break ; // Stop the middleware loop if `stopMiddlewares()` is called.
114- }
96+ const beforeMiddlewares = prepared . middlewares . filter (
97+ ( m ) => m . data . beforeExecute ,
98+ ) ;
99+
100+ let beforeMiddlewaresStopped = false ;
101+
102+ // Run middleware before command execution
103+ if ( beforeMiddlewares . length ) {
104+ await provideContext ( env , async ( ) => {
105+ for ( const middleware of beforeMiddlewares ) {
106+ try {
107+ await middleware . data . beforeExecute ( middlewareCtx ) ;
108+ } catch ( e ) {
109+ if ( isErrorType ( e , CommandKitErrorCodes . StopMiddlewares ) ) {
110+ beforeMiddlewaresStopped = true ;
111+ Logger . debug (
112+ `Middleware propagation stopped for command "${ middlewareCtx . commandName } ". stopMiddlewares() was called inside a beforeExecute function at "${ middleware . middleware . relativePath } "` ,
113+ ) ;
114+ break ; // Stop the middleware loop if `stopMiddlewares()` is called.
115+ }
116+
117+ if (
118+ isErrorType ( e , [
119+ CommandKitErrorCodes . ForwardedCommand ,
120+ CommandKitErrorCodes . InvalidCommandPrefix ,
121+ ] )
122+ ) {
123+ continue ;
124+ }
115125
116- if (
117- isErrorType ( e , [
118- CommandKitErrorCodes . ForwardedCommand ,
119- CommandKitErrorCodes . InvalidCommandPrefix ,
120- ] )
121- ) {
122- continue ;
126+ throw e ;
123127 }
124-
125- throw e ;
126128 }
127- }
128- } ) ;
129- }
129+ } ) ;
130+ }
130131
131- let result : any ;
132+ let result : any ;
132133
133- let stopMiddlewaresCalledInCmd = false ;
134+ let stopMiddlewaresCalledInCmd = false ;
134135
135- // If no `stopMiddlewares()` was called in a `beforeExecute` middleware, try to run the command
136- if ( ! beforeMiddlewaresStopped ) {
137- const targetData = prepared . command . data ;
138- const fn = targetData [ options ?. handler || executionMode ] ;
136+ // If no `stopMiddlewares()` was called in a `beforeExecute` middleware, try to run the command
137+ if ( ! beforeMiddlewaresStopped ) {
138+ const targetData = prepared . command . data ;
139+ const fn = targetData [ options ?. handler || executionMode ] ;
139140
140- if ( ! fn ) {
141- Logger . warn (
142- `Command ${ prepared . command . command . name } has no handler for ${ executionMode } ` ,
143- ) ;
144- }
141+ if ( ! fn ) {
142+ Logger . warn (
143+ `Command ${ prepared . command . command . name } has no handler for ${ executionMode } ` ,
144+ ) ;
145+ }
146+
147+ const analytics = commandkit . analytics ;
145148
146- const analytics = commandkit . analytics ;
147-
148- if ( fn ) {
149- try {
150- const _executeCommand = makeContextAwareFunction (
151- env ,
152- async ( ) => {
153- env . registerDeferredFunction ( async ( env ) => {
154- env . markEnd ( ) ;
155- const error = env . getExecutionError ( ) ;
156- const marker = env . getMarker ( ) ;
157- const time = `${ env . getExecutionTime ( ) . toFixed ( 2 ) } ms` ;
158-
159- if ( error ) {
160- Logger . error (
161- `[${ marker } - ${ time } ] Error executing command: ${ error . stack || error } ` ,
149+ if ( fn ) {
150+ try {
151+ const _executeCommand = makeContextAwareFunction (
152+ env ,
153+ async ( ) => {
154+ env . registerDeferredFunction ( async ( env ) => {
155+ env . markEnd ( ) ;
156+ const error = env . getExecutionError ( ) ;
157+ const marker = env . getMarker ( ) ;
158+ const time = `${ env . getExecutionTime ( ) . toFixed ( 2 ) } ms` ;
159+
160+ if ( error ) {
161+ Logger . error (
162+ `[${ marker } - ${ time } ] Error executing command: ${ error . stack || error } ` ,
163+ ) ;
164+
165+ const commandName =
166+ prepared . command ?. data ?. command ?. name ??
167+ prepared . command . command . name ;
168+
169+ await analytics . track ( {
170+ name : AnalyticsEvents . COMMAND_EXECUTION ,
171+ id : commandName ,
172+ data : {
173+ error : true ,
174+ executionTime : env . getExecutionTime ( ) . toFixed ( 2 ) ,
175+ type : executionMode ,
176+ command : commandName ,
177+ } ,
178+ } ) ;
179+
180+ return ;
181+ }
182+
183+ Logger . info (
184+ `[${ marker } - ${ time } ] Command executed successfully` ,
162185 ) ;
163186
164187 const commandName =
@@ -169,130 +192,115 @@ export class AppCommandRunner {
169192 name : AnalyticsEvents . COMMAND_EXECUTION ,
170193 id : commandName ,
171194 data : {
172- error : true ,
195+ error : false ,
173196 executionTime : env . getExecutionTime ( ) . toFixed ( 2 ) ,
174197 type : executionMode ,
175198 command : commandName ,
176199 } ,
177200 } ) ;
178-
179- return ;
180- }
181-
182- Logger . info (
183- `[${ marker } - ${ time } ] Command executed successfully` ,
184- ) ;
185-
186- const commandName =
187- prepared . command ?. data ?. command ?. name ??
188- prepared . command . command . name ;
189-
190- await analytics . track ( {
191- name : AnalyticsEvents . COMMAND_EXECUTION ,
192- id : commandName ,
193- data : {
194- error : false ,
195- executionTime : env . getExecutionTime ( ) . toFixed ( 2 ) ,
196- type : executionMode ,
197- command : commandName ,
198- } ,
199201 } ) ;
200- } ) ;
201202
202- return fn ( middlewareCtx . clone ( ) ) ;
203- } ,
204- this . #finalizer. bind ( this ) ,
205- ) ;
206-
207- const executeCommand =
208- runCommand != null
209- ? ( runCommand as RunCommand ) ( _executeCommand )
210- : _executeCommand ;
211-
212- env . markStart ( prepared . command . data . command . name ) ;
213-
214- const res = await commandkit . plugins . execute ( async ( ctx , plugin ) => {
215- return plugin . executeCommand (
216- ctx ,
217- env ,
218- source ,
219- prepared ,
220- executeCommand ,
203+ return fn ( middlewareCtx . clone ( ) ) ;
204+ } ,
205+ this . #finalizer. bind ( this ) ,
221206 ) ;
222- } ) ;
223207
224- if ( ! res ) {
225- result = await executeCommand ( ) ;
226- }
227- } catch ( e ) {
228- if ( isErrorType ( e , CommandKitErrorCodes . StopMiddlewares ) ) {
229- stopMiddlewaresCalledInCmd = true ;
230- Logger . debug (
231- `Middleware propagation stopped for command "${ middlewareCtx . commandName } ". stopMiddlewares() was called by the command itself` ,
208+ const executeCommand =
209+ runCommand != null
210+ ? ( runCommand as RunCommand ) ( _executeCommand )
211+ : _executeCommand ;
212+
213+ env . markStart ( prepared . command . data . command . name ) ;
214+
215+ const res = await commandkit . plugins . execute (
216+ async ( ctx , plugin ) => {
217+ return plugin . executeCommand (
218+ ctx ,
219+ env ,
220+ source ,
221+ prepared ,
222+ executeCommand ,
223+ ) ;
224+ } ,
232225 ) ;
233- } else if ( ! isErrorType ( e , CommandKitErrorCodes . ForwardedCommand ) ) {
234- if ( shouldThrowOnError ) {
235- throw e ;
236- }
237- Logger . error ( e ) ;
238- }
239- }
240- }
241- } else {
242- result = {
243- error : true ,
244- message :
245- 'Command execution was cancelled by a beforeExecute middleware.' ,
246- } ;
247- }
248226
249- const afterMiddlewares = prepared . middlewares . filter (
250- ( m ) => m . data . afterExecute ,
251- ) ;
252-
253- // Run middleware after command execution only if `stopMiddlewares()` wasn't
254- // called in either `beforeExecute` middleware or in the command itself.
255- if (
256- ! beforeMiddlewaresStopped &&
257- ! stopMiddlewaresCalledInCmd &&
258- afterMiddlewares . length
259- ) {
260- await provideContext ( env , async ( ) => {
261- for ( const middleware of afterMiddlewares ) {
262- try {
263- await middleware . data . afterExecute ( middlewareCtx ) ;
227+ if ( ! res ) {
228+ result = await executeCommand ( ) ;
229+ }
264230 } catch ( e ) {
265231 if ( isErrorType ( e , CommandKitErrorCodes . StopMiddlewares ) ) {
232+ stopMiddlewaresCalledInCmd = true ;
266233 Logger . debug (
267- `Middleware propagation stopped for command "${ middlewareCtx . commandName } ". stopMiddlewares() was called inside an afterExecute function at " ${ middleware . middleware . relativePath } " ` ,
234+ `Middleware propagation stopped for command "${ middlewareCtx . commandName } ". stopMiddlewares() was called by the command itself ` ,
268235 ) ;
269- break ; // Stop the afterExecute middleware loop if `stopMiddlewares()` is called.
236+ } else if ( ! isErrorType ( e , CommandKitErrorCodes . ForwardedCommand ) ) {
237+ if ( shouldThrowOnError ) {
238+ throw e ;
239+ }
240+ Logger . error ( e ) ;
270241 }
271- throw e ;
272242 }
273243 }
274- } ) ;
275- }
244+ } else {
245+ result = {
246+ error : true ,
247+ message :
248+ 'Command execution was cancelled by a beforeExecute middleware.' ,
249+ } ;
250+ }
276251
277- return result ;
252+ const afterMiddlewares = prepared . middlewares . filter (
253+ ( m ) => m . data . afterExecute ,
254+ ) ;
255+
256+ // Run middleware after command execution only if `stopMiddlewares()` wasn't
257+ // called in either `beforeExecute` middleware or in the command itself.
258+ if (
259+ ! beforeMiddlewaresStopped &&
260+ ! stopMiddlewaresCalledInCmd &&
261+ afterMiddlewares . length
262+ ) {
263+ await provideContext ( env , async ( ) => {
264+ for ( const middleware of afterMiddlewares ) {
265+ try {
266+ await middleware . data . afterExecute ( middlewareCtx ) ;
267+ } catch ( e ) {
268+ if ( isErrorType ( e , CommandKitErrorCodes . StopMiddlewares ) ) {
269+ Logger . debug (
270+ `Middleware propagation stopped for command "${ middlewareCtx . commandName } ". stopMiddlewares() was called inside an afterExecute function at "${ middleware . middleware . relativePath } "` ,
271+ ) ;
272+ break ; // Stop the afterExecute middleware loop if `stopMiddlewares()` is called.
273+ }
274+ throw e ;
275+ }
276+ }
277+ } ) ;
278+ }
279+
280+ return result ;
281+ } finally {
282+ await this . #finalizer( env , false ) ;
283+ }
278284 }
279285
280286 /**
281287 * @private
282288 * @internal
283289 * Finalizes command execution by running deferred functions and plugin cleanup.
284290 */
285- async #finalizer( ) {
286- const env = useEnvironment ( ) ;
291+ async #finalizer( env ?: CommandKitEnvironment , runPlugins = true ) {
292+ env ?? = useEnvironment ( ) ;
287293
288294 await env . runDeferredFunctions ( ) ;
289295
290296 env . clearAllDeferredFunctions ( ) ;
291297
292298 // plugins may have their own deferred function, useful for cleanup or post-command analytics
293- await this . handler . commandkit . plugins . execute ( async ( ctx , plugin ) => {
294- await plugin . onAfterCommand ( ctx , env ) ;
295- } ) ;
299+ if ( runPlugins ) {
300+ await this . handler . commandkit . plugins . execute ( async ( ctx , plugin ) => {
301+ await plugin . onAfterCommand ( ctx , env ) ;
302+ } ) ;
303+ }
296304 }
297305
298306 /**
0 commit comments