import { Meteor } from 'meteor/meteor'; import type { IMessage, SlashCommand, SlashCommandOptions, RequiredField, SlashCommandPreviewItem, SlashCommandPreviews, } from '@rocket.chat/core-typings'; interface ISlashCommandAddParams { command: string; callback?: SlashCommand['callback']; options?: SlashCommandOptions; result?: SlashCommand['result']; providesPreview?: boolean; previewer?: SlashCommand['previewer']; previewCallback?: SlashCommand['previewCallback']; appId?: string; description?: string; } export const slashCommands = { commands: {} as Record, add({ command, callback, options = {}, result, providesPreview = false, previewer, previewCallback, appId, description = '', }: ISlashCommandAddParams): void { if (this.commands[command]) { return; } this.commands[command] = { command, callback, params: options.params, description: options.description || description, permission: options.permission, clientOnly: options.clientOnly || false, result, providesPreview: Boolean(providesPreview), previewer, previewCallback, appId, } as SlashCommand; }, async run({ command, message, params, triggerId, userId, }: { command: string; params: string; message: RequiredField, 'rid' | '_id'>; userId: string; triggerId?: string | undefined; }): Promise { const cmd = this.commands[command]; if (typeof cmd?.callback !== 'function') { return; } if (!message?.rid) { throw new Meteor.Error('invalid-command-usage', 'Executing a command requires at least a message with a room id.'); } return cmd.callback({ command, params, message, triggerId, userId }); }, async getPreviews( command: string, params: string, message: RequiredField, 'rid'>, ): Promise { const cmd = this.commands[command]; if (typeof cmd?.previewer !== 'function') { return; } if (!message?.rid) { throw new Meteor.Error('invalid-command-usage', 'Executing a command requires at least a message with a room id.'); } const previewInfo = await cmd.previewer(command, params, message); if (!previewInfo?.items?.length) { return; } // A limit of ten results, to save time and bandwidth if (previewInfo.items.length >= 10) { previewInfo.items = previewInfo.items.slice(0, 10); } return previewInfo; }, async executePreview( command: string, params: string, message: Pick & Partial>, preview: SlashCommandPreviewItem, triggerId?: string, ) { const cmd = this.commands[command]; if (typeof cmd?.previewCallback !== 'function') { return; } if (!message?.rid) { throw new Meteor.Error('invalid-command-usage', 'Executing a command requires at least a message with a room id.'); } // { id, type, value } if (!preview.id || !preview.type || !preview.value) { throw new Meteor.Error('error-invalid-preview', 'Preview Item must have an id, type, and value.'); } return cmd.previewCallback(command, params, message, preview, triggerId); }, }; declare module '@rocket.chat/ui-contexts' { // eslint-disable-next-line @typescript-eslint/naming-convention interface ServerMethods { slashCommand(params: { cmd: string; params: string; msg: IMessage; triggerId: string }): unknown; } }