Skip to main content

Danh sách Decorators

Danh sách đầy đủ các decorators trong Nezon và cách sử dụng.

Command Decorators

@Command

Định nghĩa text command.

@Command(name: string | NezonCommandOptions)

Type:

interface NezonCommandOptions {
name: string;
aliases?: string[];
prefix?: string;
}

Ví dụ:

@Command('ping')
@Command({ name: 'ping', aliases: ['pong'], prefix: '!' })

Xem thêm: @Command

Component Decorators

@Component

Xử lý component interactions (buttons, selects, etc.).

@Component(options: NezonComponentOptions | string)

Type:

interface NezonComponentOptions {
pattern: string;
id?: string;
}

Ví dụ:

@Component('click/confirm')
@Component({ pattern: '/user/:id/:action' })

Xem thêm: @Component

Event Decorators

@On

Lắng nghe event mỗi lần xảy ra.

@On(event: string)

Ví dụ:

@On(Events.ChannelMessage)

Xem thêm: @On, @Once

@OnMention

Lắng nghe riêng trường hợp bot được mention trong ChannelMessage.

@OnMention()

Cách hoạt động:

  • Nội bộ Nezon lắng nghe Events.ChannelMessage
  • Với mỗi message, Nezon kiểm tra message.mentions có phần tử nào có user_id === botId (config từ NezonModule.forRoot({ botId })) hay không
  • Nếu có, Nezon emit event nội bộ nezon:mention và gọi tất cả handler được đánh dấu @OnMention()

Ví dụ:

@OnMention()
async onBotMention(
@MessageContent() content: string,
@User('username') username: string | undefined,
) {
console.log(`Bot được mention bởi ${username}: ${content}`);
}

Bạn vẫn có thể dùng đầy đủ các decorator param trong @OnMention() giống như @On() / @Once():
@ChannelMessagePayload(), @EventPayload(), @Channel(), @Clan(), @User(), @MessageContent(), @Mentions(), @Attachments(), @Client(), @AutoContext(), @NezonUtils(), ...

@Once

Lắng nghe event một lần duy nhất.

@Once(event: string)

Ví dụ:

@Once('Ready')

Xem thêm: @On, @Once

Parameter Decorators

@Args

Lấy tất cả arguments từ command.

@Args(): ParameterDecorator
// Trả về: Nezon.Args = string[]

Ví dụ:

@Command('greet')
async greet(@Args() args: Nezon.Args) {
// args = ['John', 'Doe']
}

@Arg

Lấy argument cụ thể theo index.

@Arg(index: number): ParameterDecorator
// Trả về: string | undefined

Ví dụ:

@Command('greet')
async greet(@Arg(0) name: string | undefined) {
// name = 'John'
}

@Attachments

Lấy danh sách file đính kèm từ message.

@Attachments(index?: number): ParameterDecorator
// Không có index: Nezon.Attachments
// Có index: Nezon.Attachment | undefined

Ví dụ:

@Command('inspect')
async inspect(
@Attachments() files: Nezon.Attachments,
@Attachments(0) firstFile: Nezon.Attachment | undefined,
) {
// ...
}

@Mentions

Lấy danh sách mentions từ message.

@Mentions(index?: number): ParameterDecorator
// Không có index: Nezon.Mentions
// Có index: Nezon.Mention | undefined

Ví dụ:

@Command('inspect')
async inspectMentions(
@Mentions() mentions: Nezon.Mentions,
@Mentions(0) firstMention: Nezon.Mention | undefined,
) {
// ...
}

@MessageContent

Lấy toàn bộ nội dung message (bao gồm cả command).

@MessageContent(): ParameterDecorator
// Trả về: string | undefined

Ví dụ:

@Command('echo')
async echo(@MessageContent() content: string | undefined) {
// content = '*echo Hello World'
}

@AutoContext

Lấy ManagedMessage, DMHelper và ChannelHelper với các methods tiện dụng.

@AutoContext(key?: 'message' | 'dm' | 'channel'): ParameterDecorator
// Không có key: Trả về Nezon.AutoContext = [ManagedMessage, DMHelper, ChannelHelper]
// Với key 'message': Trả về Nezon.AutoContextType.Message
// Với key 'dm': Trả về Nezon.AutoContextType.DM
// Với key 'channel': Trả về Nezon.AutoContextType.Channel

Cách 1: Lấy toàn bộ tuple (backward compatible)

@Command('ping')
async ping(@AutoContext() [managedMessage]: Nezon.AutoContext) {
await managedMessage.reply(SmartMessage.text('pong!'));
}

Cách 2: Lấy phần tử cụ thể bằng key

@Command('dm')
async sendDM(
@Args() args: Nezon.Args,
@AutoContext('message') managedMessage: Nezon.AutoContextType.Message,
@AutoContext('dm') dm: Nezon.AutoContextType.DM,
) {
const userId = args[0];
await dm.send(userId, SmartMessage.text('Hello via DM!'));
}

Ví dụ 3: Channel helper

@Command('broadcast')
async broadcast(
@AutoContext('channel') channel: Nezon.AutoContextType.Channel,
) {
if (!channel) return;
await channel.send(SmartMessage.text('Tin nhắn mới trong channel hiện tại!'));
}

@Command('broadcast-to')
async broadcastTo(
@Args() args: Nezon.Args,
@AutoContext('channel') channel: Nezon.AutoContextType.Channel,
) {
const [channelId] = args;
if (!channel || !channelId) {
return;
}
await channel
.find(channelId)
.send(SmartMessage.text(`Gửi thông báo tới channel ${channelId}`));
}

Type definitions:

  • Nezon.AutoContext - Tuple type [ManagedMessage, DMHelper, ChannelHelper]
  • Nezon.AutoContextType.Message - Type cho ManagedMessage
  • Nezon.AutoContextType.DM - Type cho DMHelper
  • Nezon.AutoContextType.Channel - Type cho ChannelHelper

Lưu ý về ManagedMessage

ManagedMessage đại diện cho message của context hiện tại:

  • Với text commands, đây chính là tin nhắn người dùng gửi, nên bạn chỉ nên dùng reply(), sendDM(), hoặc react(). Các method như update()/delete() sẽ throw error nếu không phải message của bot.
  • Với component handlers (hoặc khi dùng @ComponentTarget), ManagedMessage trỏ tới message do bot gửi, vì vậy bạn có thể gọi update() hoặc delete() để chỉnh sửa/xóa message của bot.
  • Reaction methods (react(), addReaction(), removeReaction()) hoạt động với cả message của user và bot.

Best practice: đặt tên biến là managedMessage hoặc tương tự để phân biệt với raw payload (ChannelMessagePayload).

Lưu ý về ChannelHelper & AutoContext trong event

  • Với @On(Events.ChannelMessage)@OnMention(), @AutoContext() hoạt động tương tự command: bạn có thể dùng đầy đủ [ManagedMessage, DMHelper, ChannelHelper].
  • Với các event khác (không phải channel message), Nezon không có thông tin channel/message cụ thể nên chỉ khởi tạo được DM helper, hai phần tử còn lại sẽ là null.

@Message

Lấy Message entity từ Mezon SDK.

@Message(key?: string): ParameterDecorator
// Trả về: Nezon.Message | undefined
// Nếu có key: trả về message[key]

Ví dụ:

@Command('info')
async info(@Message() message: Nezon.Message | undefined) {
// message entity
}

@Command('info')
async info(@Message('id') messageId: string | undefined) {
// message.id
}

@ChannelMessagePayload

Lấy raw ChannelMessage payload.

@ChannelMessagePayload(): ParameterDecorator
// Trả về: Nezon.ChannelMessage

Ví dụ:

@On(Events.ChannelMessage)
async onMessage(@ChannelMessagePayload() payload: Nezon.ChannelMessage) {
// payload.message_id, payload.channel_id, etc.
}

@Channel

Lấy Channel entity.

@Channel(key?: string): ParameterDecorator
// Trả về: Nezon.Channel | undefined
// Nếu có key: trả về channel[key]

Ví dụ:

@Command('info')
async info(@Channel() channel: Nezon.Channel | undefined) {
// channel entity
}

@Command('info')
async info(@Channel('name') channelName: string | undefined) {
// channel.name
}

@Clan

Lấy Clan entity.

@Clan(): ParameterDecorator
// Trả về: Nezon.Clan | undefined

Ví dụ:

@Command('info')
async info(@Clan() clan: Nezon.Clan | undefined) {
// clan entity
}

@User

Lấy User entity.

@User(key?: string): ParameterDecorator
// Trả về: Nezon.User | undefined
// Nếu có key: trả về user[key]

Ví dụ:

@Command('info')
async info(@User() user: Nezon.User | undefined) {
// user entity
}

@Command('info')
async info(@User('username') username: string | undefined) {
// user.username
}

@Client

Lấy MezonClient instance.

@Client(): ParameterDecorator
// Trả về: Nezon.Client = MezonClient

Ví dụ:

@Command('info')
async info(@Client() client: Nezon.Client) {
// client instance
}

@ComponentPayload

Lấy raw ComponentPayload từ button click.

@ComponentPayload(): ParameterDecorator
// Trả về: Nezon.ComponentPayload = MessageButtonClicked

Ví dụ:

@Component('click/confirm')
async confirm(@ComponentPayload() payload: Nezon.ComponentPayload) {
// payload.button_id, payload.user_id, etc.
}

@ComponentParams

Lấy tất cả parameters từ component pattern.

@ComponentParams(paramName?: string): ParameterDecorator
// Không có paramName: trả về tất cả params
// Có paramName: trả về param cụ thể
// Trả về: Nezon.ComponentParams = string[] | Record<string, string>

Ví dụ:

@Component({ pattern: '/user/:id/:action' })
async action(
@ComponentParams() allParams: Record<string, string> | undefined,
@ComponentParams('id') userId: string | undefined,
) {
// allParams = { id: '123', action: 'kick' }
// userId = '123'
}

@ComponentParam

Lấy parameter cụ thể theo index hoặc name.

@ComponentParam(positionOrName: number | string): ParameterDecorator
// number: lấy theo index
// string: lấy theo tên (named parameter)
// Trả về: string | undefined

Ví dụ:

@Component({ pattern: '/user/:id/:action' })
async action(
@ComponentParam(0) firstParam: string | undefined, // '123'
@ComponentParam('id') userId: string | undefined, // '123'
@ComponentParam('action') action: string | undefined, // 'kick'
) {
// ...
}

@ComponentTarget

Lấy Message entity đã được cache từ component click.

@ComponentTarget(): ParameterDecorator
// Trả về: Nezon.Message | undefined

Ví dụ:

@Component('click/confirm')
async confirm(@ComponentTarget() target: Nezon.Message | undefined) {
// target message đã được cache
}

@FormData

Đọc dữ liệu form (các input được tạo bằng EmbedBuilder.addTextField/addSelectField) khi người dùng submit thông qua button/component.

@FormData(field?: string): ParameterDecorator
// Không có field: trả về Record<string, string>
// Có field: trả về giá trị cụ thể (string | undefined)
@Component('/poll/create')
async onPollCreate(
@FormData() form: Nezon.FormData | undefined,
@FormData('title') title: string | undefined,
@AutoContext('message') message: Nezon.AutoContextType.Message,
) {
await message.reply(
SmartMessage.text(
[
'🎯 Poll form data:',
`Tiêu đề: ${title ?? 'N/A'}`,
`Option 1: ${form?.option_1 ?? 'N/A'}`,
`Expired: ${form?.expired ?? '168'} giờ`,
].join('\n'),
),
);
}

Khi dùng ButtonBuilder.onClick, bạn cũng có thể đọc context.formData.

@EventPayload

Lấy event payload từ @On hoặc @Once handlers.

@EventPayload(): ParameterDecorator
// Trả về: Event payload (type depends on event)

Ví dụ:

@On(Events.TokenSend)
async onTokenSend(@EventPayload() payload: Nezon.TokenSendPayload) {
// payload: TokenSentEvent
}

@On(Events.AddClanUser)
async onAddClanUser(@EventPayload() payload: Nezon.AddClanUserPayload) {
// payload: { user_id: string; clan_id: string; ... }
}

Bộ lọc / Giới hạn (Guards & Restrict)

1. Global restrict (scope toàn bot)

Khi khai báo NezonModule.forRoot, bạn có thể giới hạn phạm vi hoạt động của bot:

NezonModule.forRoot({
token: process.env.MEZON_TOKEN ?? "",
botId: process.env.MEZON_BOT_ID ?? "",
restricts: {
clans: ["1840666443260104704"],
channels: ["1840678533651763200"],
users: ["1831557527519629312"],
},
});
  • clans: chỉ xử lý command/component/event trong các clan này.
  • channels: chỉ xử lý trong các channel ID này.
  • users: chỉ nhận lệnh/sự kiện từ các user ID này.

Áp dụng cho:

  • @Command (command handlers)
  • @Component (component handlers)
  • @On, @Once, @OnMention (event handlers)

2. @Restrict – scope theo class & function

Decorator @Restrict() cho phép bạn set scope chi tiết hơn, override/merge với global:

@Restrict({
clans: string[];
channels?: string[];
users?: string[];
})
  • Class-level: áp dụng cho toàn bộ handler trong class.
  • Method-level: áp dụng riêng cho 1 @Command, @Component, @On, @Once, @OnMention.
  • Khi có nhiều lớp (global + class + method), các mảng sẽ được merge (union) rồi mới kiểm tra.

Ví dụ:

@Injectable()
@Restrict({ clans: ["clan-A"] }) // tất cả handler trong class chỉ chạy ở clan-A
export class ExampleCommandHandlers {
@Command("ping")
async ping() {}

@Restrict({ users: ["admin-id"] }) // chỉ user này mới gọi được lệnh
@Command("admin-only")
async adminOnly() {}
}

3. NestJS Guards – @UseGuards cho Nezon handler

Nezon hỗ trợ @UseGuards() của NestJS trên:

  • @Command handlers
  • @Component handlers
  • @On, @Once, @OnMention event handlers

Guard được lấy từ metadata Nest (@UseGuards) ở classmethod, sau đó được gọi trước khi vào handler.

Context trong Guard cụ thể là gì?

  • Guard luôn nhận ExecutionContext giống NestJS:

    • context.getType() sẽ là "rpc" cho tất cả handler của Nezon.
    • context.getArgs() là mảng các tham số gốc mà Nezon truyền cho handler nội bộ.
  • Command handler (@Command):

    • const [ctx] = context.getArgs() as [Nezon.NezonCommandContext];
    • ctx chứa:
      • message: Nezon.ChannelMessage (payload gốc từ Mezon)
      • client: MezonClient
      • args: string[] – danh sách argument sau prefix/command
      • reply(), getChannel(), getClan(), getUser(), getMessage(), getMessageByIds() – helper đã được bind sẵn
  • Component handler (@Component):

    • const [ctx] = context.getArgs() as [Nezon.NezonComponentContext];
    • ctx chứa:
      • payload: MessageButtonClicked (event click button từ Mezon)
      • client: MezonClient
      • params: string[] – params từ pattern (vd /user/:id/:action)
      • namedParams?: Record<string, string> – params dạng object nếu dùng :id
      • match?: RegExpMatchArray | null
      • cache?: Map<symbol, unknown> – cache nội bộ cho handler
  • Event handler (@On, @Once, @OnMention):

    • const args = context.getArgs();
    • Tùy event:
      • Với Events.ChannelMessage / @OnMention():
        • const [payload] = args as [Nezon.ChannelMessage];
      • Với Events.TokenSend:
        • const [payload] = args as [Nezon.TokenSendPayload];
      • Với các event khác: args[0] luôn là payload gốc mà Mezon bắn ra.

Nhờ đó, bạn có thể viết guard phức tạp (kiểm tra quyền, trạng thái bot, payload, v.v.) mà không cần thay đổi handler logic.

Ví dụ Guard đơn giản:

@Injectable()
class ClanGuard implements CanActivate {
canActivate(ctx: ExecutionContext): boolean {
const [context] = ctx.getArgs() as [Nezon.NezonCommandContext];
return context.message.clan_id === "1840666443260104704";
}
}

@Injectable()
@UseGuards(ClanGuard) // áp cho tất cả command trong class
export class ExampleCommandHandlers {
@Command("ping")
async ping(@AutoContext() [message]: Nezon.AutoContext) {
await message.reply(SmartMessage.text("pong!"));
}

@UseGuards(OtherGuard) // chỉ áp riêng cho lệnh này
@Command("secure")
async secure(@AutoContext() [message]: Nezon.AutoContext) {
await message.reply(SmartMessage.text("secured!"));
}
}

Thứ tự chạy:

  1. Kiểm tra restricts (global + class + method)
  2. Chạy tất cả NestJS Guards (@UseGuards)
  3. Nếu pass hết → mới vào handler logic.

Bảng tóm tắt

DecoratorTypeUse Case
@CommandMethodĐịnh nghĩa command
@ComponentMethodXử lý component
@OnMethodLắng nghe event
@OnceMethodLắng nghe event một lần
@ArgsParameterTất cả arguments
@ArgParameterArgument cụ thể
@MessageContentParameterNội dung message
@AutoContextParameterManagedMessage
@MessageParameterMessage entity
@ChannelMessagePayloadParameterRaw message payload
@ChannelParameterChannel entity
@ClanParameterClan entity
@UserParameterUser entity
@ClientParameterMezonClient
@ComponentPayloadParameterRaw component payload
@ComponentParamsParameterComponent parameters
@ComponentParamParameterComponent parameter cụ thể
@ComponentTargetParameterTarget message (cached)
@EventPayloadParameterEvent payload (typed)
@MezonClientParameterMezonClient instance
@NezonUtilsParameterNezonUtilsService instance

Xem thêm