import * as Sentry from '@sentry/node' ; import { Interaction , Structures } from 'detritus-client' ; import { ApplicationCommandTypes , ApplicationCommandOptionTypes , InteractionCallbackTypes , MessageFlags , } from 'detritus-client/lib/constants' ; import { Embed , Markup } from 'detritus-client/lib/utils' ; import { Response } from 'detritus-rest' ; import { EmbedColors , PermissionsText } from '../../constants' ; import { DefaultParameters , Parameters , editOrReply } from '../../utils' ; export class BaseInteractionCommand < ParsedArgsFinished = Interaction . ParsedArgs > extends Interaction . InteractionCommand < ParsedArgsFinished > { error = 'Command' ; onAutoCompleteError ( context , error ) { Sentry . captureException ( error ) ; } onLoadingTrigger ( context ) { if ( context . responded ) { return ; } if ( this . triggerLoadingAsEphemeral ) { return context . respond ( InteractionCallbackTypes . DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE , { flags : MessageFlags . EPHEMERAL } ) ; } return context . respond ( InteractionCallbackTypes . DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE ) ; } onDmBlocked ( context ) { const command = Markup . codestring ( context . name ) ; return context . editOrRespond ( { content : `⚠ ${ this . error } \`${ command }\` cannot be used in a DM.` , flags : MessageFlags . EPHEMERAL , } ) ; } onCancelRun ( context , args ) { const command = Markup . codestring ( context . name ) ; return context . editOrRespond ( { content : `⚠ ${ this . error } \`${ command }\` error strangely, give me a report.` , flags : MessageFlags . EPHEMERAL , } ) ; } onPermissionsFailClient ( context , failed ) { const permissions = [ ] ; for ( let permission of failed ) { const key = String ( permission ) ; if ( key in PermissionsText ) { permissions . push ( `\`${ PermissionsText [ key ] }\`` ) ; } else { permissions . push ( `\`(Unknown: ${ permission })\`` ) ; } } const command = Markup . codestring ( context . name ) ; return context . editOrRespond ( { content : `⚠ ${ this . error } ${ command } requires the bot to have ${ permissions . join ( ', ' ) } to work.` , } ) ; } onPermissionsFail ( context , failed ) { const permissions = [ ] ; for ( let permission of failed ) { const key = String ( permission ) ; if ( key in PermissionsText ) { permissions . push ( `\`${ PermissionsText [ key ] }\`` ) ; } else { permissions . push ( `\`(Unknown: ${ permission })\`` ) ; } } const command = Markup . codestring ( context . name ) ; return context . editOrRespond ( { content : `⚠ ${ this . error } ${ command } requires you to have ${ permissions . join ( ', ' ) }.` , flags : MessageFlags . EPHEMERAL , } ) ; } async onRunError ( context , args , error ) { const embed = new Embed ( ) ; embed . setColor ( EmbedColors . ERROR ) ; embed . setTitle ( `⚠ ${ this . error } Command Error` ) ; const description = [ ] ; if ( error . response ) { const response = error . response ; try { const information = await response . json ( ) as any ; description . push ( error . message || error . stack ) ; if ( 'errors' in information ) { for ( let key in information . errors ) { const value = information . errors [ key ] ; let message ; if ( typeof ( value ) === 'object' ) { message = JSON . stringify ( value ) ; } else { message = String ( value ) ; } description . push ( `**${ key }**: ${ message }` ) ; } } if ( response . statusCode === 429 && ( ( context . rest . raw . restClient . baseUrl instanceof URL ) && ( context . rest . raw . restClient . baseUrl . host === response . request . parsedUrl . host ) ) ) { const headers = { } ; for ( let [ header , value ] of response . headers ) { if ( header . startsWith ( 'x-ratelimit' ) ) { headers [ header ] = value ; } } embed . addField ( 'Ratelimit Info' , [ '```json' , JSON . stringify ( { body : information , headers } ) , '```' , ] . join ( '\n' ) ) ; } } catch ( e ) { if ( response . statusCode === 502 ) { description . push ( 'Our api is restarting, might take a bit. Sorry ;(' ) ; } else { description . push ( `HTTP Exception: ${ response . statusCode }` ) ; const contentType = response . headers . get ( 'content-type' ) || '' ; if ( contentType . startsWith ( 'text/html' ) ) { } else { description . push ( 'Unknown Error Data' ) ; if ( contentType ) { description . push ( `**Mimetype**: ${ contentType }` ) ; } } } } } else { const message = String ( error . message || error . stack ) ; if ( message . includes ( 'reason: connect ECONNREFUSED 127.0.0.1:80' ) ) { description . push ( 'Our api is restarting, might take a bit. Sorry ;(' ) ; } else { description . push ( message ) ; } } embed . setDescription ( description . join ( '\n' ) ) ; if ( error . metadata ) { embed . addField ( 'Metadata' , [ '```json' , JSON . stringify ( error . metadata ) , '```' , ] . join ( '\n' ) ) ; } return context . editOrRespond ( { embed , flags : MessageFlags . EPHEMERAL , } ) ; } } export class BaseInteractionCommandOption < ParsedArgsFinished = Interaction . ParsedArgs > extends Interaction . InteractionCommandOption < ParsedArgsFinished > { error = 'Slash Command' ; type = ApplicationCommandOptionTypes . SUB_COMMAND ; onCancelRun ( context , args ) { const command = Markup . codestring ( context . name ) ; return context . editOrRespond ( { content : `⚠ ${ this . error } \`${ command }\` error strangely, give me a report.` , flags : MessageFlags . EPHEMERAL , } ) ; } } export class BaseInteractionImageCommandOption < ParsedArgsFinished = Interaction . ParsedArgs > extends BaseInteractionCommandOption < ParsedArgsFinished > { constructor ( data = { } ) { super ( { ... data , options : [ ... ( data . options || [ ] ) , { name : 'image' , description : 'Emoji/Image URL/User' , label : 'url' , default : DefaultParameters . lastImageUrl , value : Parameters . lastImageUrl } , ] , } ) ; } onBeforeRun ( context , args ) { if ( args . url ) { context . metadata = Object . assign ( { } , context . metadata , { contentUrl : args . url } ) ; } return ! ! args . url ; } onCancelRun ( context , args ) { if ( args . url === undefined ) { return editOrReply ( context , '⚠ Unable to find any images in the last 50 messages.' ) ; } else if ( args . url === null ) { return editOrReply ( context , '⚠ Unable to find that user or it was an invalid url.' ) ; } return super . onCancelRun ( context , args ) ; } } export class BaseInteractionCommandOptionGroup < ParsedArgsFinished = Interaction . ParsedArgs > extends Interaction . InteractionCommandOption < ParsedArgsFinished > { error = 'Slash Command' ; type = ApplicationCommandOptionTypes . SUB_COMMAND_GROUP ; onCancelRun ( context , args ) { const command = Markup . codestring ( context . name ) ; return context . editOrRespond ( { content : `⚠ ${ this . error } \`${ command }\` error strangely, give me a report.` , flags : MessageFlags . EPHEMERAL , } ) ; } } export class BaseSlashCommand < ParsedArgsFinished = Interaction . ParsedArgs > extends BaseInteractionCommand < ParsedArgsFinished > { error = 'Slash Command' ; type = ApplicationCommandTypes . CHAT_INPUT ; triggerLoadingAfter = 1000 ; } export interface ContextMenuMessageArgs { message : Structures . Message ; } export class BaseContextMenuMessageCommand extends BaseInteractionCommand < ContextMenuMessageArgs > { error = 'Message Context Menu' ; type = ApplicationCommandTypes . MESSAGE ; global = true ; permissionsIgnoreClientOwner = true ; triggerLoadingAfter = 1000 ; triggerLoadingAsEphemeral = true ; constructor ( data = { } ) { super ( Object . assign ( { guildIds : [ '178313653177548800' , '621077547471601685' ] } , data ) ) ; } } export interface ContextMenuUserArgs { member ? : Structures . Member ; user : Structures . User ; } export class BaseContextMenuUserCommand extends BaseInteractionCommand < ContextMenuUserArgs > { error = 'User Context Menu' ; type = ApplicationCommandTypes . USER ; global = true ; permissionsIgnoreClientOwner = true ; triggerLoadingAsEphemeral = true ; constructor ( data = { } ) { super ( Object . assign ( { guildIds : [ '178313653177548800' ] } , data ) ) ; } }