novaapp-sdk 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +1876 -284
- package/dist/index.d.ts +1876 -284
- package/dist/index.js +2290 -482
- package/dist/index.mjs +2269 -481
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -60,6 +60,59 @@ interface Member {
|
|
|
60
60
|
isBot: boolean;
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
|
+
type ChannelType = 'TEXT' | 'VOICE' | 'ANNOUNCEMENT' | 'FORUM' | 'STAGE';
|
|
64
|
+
interface Channel {
|
|
65
|
+
id: string;
|
|
66
|
+
name: string;
|
|
67
|
+
type: ChannelType;
|
|
68
|
+
serverId: string | null;
|
|
69
|
+
topic: string | null;
|
|
70
|
+
position: number;
|
|
71
|
+
/** Slow-mode interval in seconds. `0` means disabled. */
|
|
72
|
+
slowMode: number;
|
|
73
|
+
createdAt: string;
|
|
74
|
+
}
|
|
75
|
+
interface Role {
|
|
76
|
+
id: string;
|
|
77
|
+
name: string;
|
|
78
|
+
color: string | null;
|
|
79
|
+
position: number;
|
|
80
|
+
serverId: string;
|
|
81
|
+
hoist: boolean;
|
|
82
|
+
permissions: Record<string, boolean>;
|
|
83
|
+
createdAt: string;
|
|
84
|
+
}
|
|
85
|
+
interface BanEntry {
|
|
86
|
+
userId: string;
|
|
87
|
+
username: string;
|
|
88
|
+
displayName: string;
|
|
89
|
+
avatar: string | null;
|
|
90
|
+
reason: string | null;
|
|
91
|
+
bannedAt: string;
|
|
92
|
+
moderatorId: string | null;
|
|
93
|
+
}
|
|
94
|
+
interface Invite {
|
|
95
|
+
code: string;
|
|
96
|
+
serverId: string;
|
|
97
|
+
creatorId: string;
|
|
98
|
+
uses: number;
|
|
99
|
+
maxUses: number | null;
|
|
100
|
+
expiresAt: string | null;
|
|
101
|
+
createdAt: string;
|
|
102
|
+
}
|
|
103
|
+
/** A message with all reaction data fetched. */
|
|
104
|
+
interface ReactionDetail {
|
|
105
|
+
emoji: string;
|
|
106
|
+
count: number;
|
|
107
|
+
users: Array<{
|
|
108
|
+
id: string;
|
|
109
|
+
username: string;
|
|
110
|
+
displayName: string;
|
|
111
|
+
avatar: string | null;
|
|
112
|
+
}>;
|
|
113
|
+
}
|
|
114
|
+
/** Bot status that can be set via `client.setStatus()`. */
|
|
115
|
+
type BotStatus = 'ONLINE' | 'IDLE' | 'DND' | 'OFFLINE';
|
|
63
116
|
interface Attachment {
|
|
64
117
|
id: string;
|
|
65
118
|
url: string;
|
|
@@ -278,6 +331,22 @@ interface PollInteractionsOptions {
|
|
|
278
331
|
limit?: number;
|
|
279
332
|
since?: string;
|
|
280
333
|
}
|
|
334
|
+
interface CreateChannelOptions {
|
|
335
|
+
name: string;
|
|
336
|
+
type?: ChannelType;
|
|
337
|
+
topic?: string;
|
|
338
|
+
position?: number;
|
|
339
|
+
slowMode?: number;
|
|
340
|
+
}
|
|
341
|
+
interface EditChannelOptions {
|
|
342
|
+
name?: string;
|
|
343
|
+
topic?: string;
|
|
344
|
+
position?: number;
|
|
345
|
+
slowMode?: number;
|
|
346
|
+
}
|
|
347
|
+
interface FetchChannelsOptions {
|
|
348
|
+
type?: ChannelType;
|
|
349
|
+
}
|
|
281
350
|
/** A raw permission record stored for a specific scope (server, role, or channel). */
|
|
282
351
|
interface BotPermissionRecord {
|
|
283
352
|
id: string;
|
|
@@ -311,6 +380,29 @@ interface PermissionsQueryOptions {
|
|
|
311
380
|
/** Narrow the scope to a specific role. */
|
|
312
381
|
roleId?: string;
|
|
313
382
|
}
|
|
383
|
+
/** A direct message sent between the bot and a user. */
|
|
384
|
+
interface DirectMessage {
|
|
385
|
+
id: string;
|
|
386
|
+
content: string;
|
|
387
|
+
/** The sender's user ID. */
|
|
388
|
+
fromId: string;
|
|
389
|
+
/** The recipient's user ID. */
|
|
390
|
+
toId: string;
|
|
391
|
+
editedAt: string | null;
|
|
392
|
+
createdAt: string;
|
|
393
|
+
}
|
|
394
|
+
/** Snapshot of a user's voice channel presence. */
|
|
395
|
+
interface VoiceState {
|
|
396
|
+
userId: string;
|
|
397
|
+
channelId: string;
|
|
398
|
+
serverId: string;
|
|
399
|
+
/** Whether the user's microphone is muted. */
|
|
400
|
+
muted: boolean;
|
|
401
|
+
/** Whether the user's audio output is deafened. */
|
|
402
|
+
deafened: boolean;
|
|
403
|
+
/** ISO timestamp when the user joined the voice channel. */
|
|
404
|
+
joinedAt: string;
|
|
405
|
+
}
|
|
314
406
|
interface NovaClientOptions {
|
|
315
407
|
/** Your bot token — starts with "nova_bot_" */
|
|
316
408
|
token: string;
|
|
@@ -354,6 +446,64 @@ declare class MessagesAPI {
|
|
|
354
446
|
typing(channelId: string): Promise<{
|
|
355
447
|
ok: true;
|
|
356
448
|
}>;
|
|
449
|
+
/**
|
|
450
|
+
* Fetch a single message by ID.
|
|
451
|
+
*
|
|
452
|
+
* @example
|
|
453
|
+
* const msg = await client.messages.fetchOne('message-id')
|
|
454
|
+
*/
|
|
455
|
+
fetchOne(messageId: string): Promise<Message>;
|
|
456
|
+
/**
|
|
457
|
+
* Pin a message in its channel.
|
|
458
|
+
* The bot must have the `messages.manage` scope.
|
|
459
|
+
*
|
|
460
|
+
* @example
|
|
461
|
+
* await client.messages.pin('message-id')
|
|
462
|
+
*/
|
|
463
|
+
pin(messageId: string): Promise<{
|
|
464
|
+
ok: true;
|
|
465
|
+
}>;
|
|
466
|
+
/**
|
|
467
|
+
* Unpin a message.
|
|
468
|
+
*
|
|
469
|
+
* @example
|
|
470
|
+
* await client.messages.unpin('message-id')
|
|
471
|
+
*/
|
|
472
|
+
unpin(messageId: string): Promise<{
|
|
473
|
+
ok: true;
|
|
474
|
+
}>;
|
|
475
|
+
/**
|
|
476
|
+
* Fetch all pinned messages in a channel.
|
|
477
|
+
*
|
|
478
|
+
* @example
|
|
479
|
+
* const pins = await client.messages.fetchPinned('channel-id')
|
|
480
|
+
*/
|
|
481
|
+
fetchPinned(channelId: string): Promise<Message[]>;
|
|
482
|
+
/**
|
|
483
|
+
* Add a reaction to a message.
|
|
484
|
+
*
|
|
485
|
+
* @example
|
|
486
|
+
* await client.messages.addReaction('message-id', '👍')
|
|
487
|
+
*/
|
|
488
|
+
addReaction(messageId: string, emoji: string): Promise<{
|
|
489
|
+
ok: true;
|
|
490
|
+
}>;
|
|
491
|
+
/**
|
|
492
|
+
* Remove the bot's reaction from a message.
|
|
493
|
+
*
|
|
494
|
+
* @example
|
|
495
|
+
* await client.messages.removeReaction('message-id', '👍')
|
|
496
|
+
*/
|
|
497
|
+
removeReaction(messageId: string, emoji: string): Promise<{
|
|
498
|
+
ok: true;
|
|
499
|
+
}>;
|
|
500
|
+
/**
|
|
501
|
+
* Fetch all reactions on a message.
|
|
502
|
+
*
|
|
503
|
+
* @example
|
|
504
|
+
* const reactions = await client.messages.fetchReactions('message-id')
|
|
505
|
+
*/
|
|
506
|
+
fetchReactions(messageId: string): Promise<ReactionDetail[]>;
|
|
357
507
|
}
|
|
358
508
|
|
|
359
509
|
declare class CommandsAPI {
|
|
@@ -460,6 +610,56 @@ declare class MembersAPI {
|
|
|
460
610
|
ban(serverId: string, userId: string, reason?: string): Promise<{
|
|
461
611
|
ok: true;
|
|
462
612
|
}>;
|
|
613
|
+
/**
|
|
614
|
+
* Unban a previously banned user.
|
|
615
|
+
* Requires the `members.ban` scope.
|
|
616
|
+
*
|
|
617
|
+
* @example
|
|
618
|
+
* await client.members.unban('server-id', 'user-id')
|
|
619
|
+
*/
|
|
620
|
+
unban(serverId: string, userId: string): Promise<{
|
|
621
|
+
ok: true;
|
|
622
|
+
}>;
|
|
623
|
+
/**
|
|
624
|
+
* Fetch the ban list for a server.
|
|
625
|
+
* Requires the `members.ban` scope.
|
|
626
|
+
*
|
|
627
|
+
* @example
|
|
628
|
+
* const bans = await client.members.listBans('server-id')
|
|
629
|
+
* for (const ban of bans) {
|
|
630
|
+
* console.log(`${ban.username} — ${ban.reason ?? 'No reason'}`)
|
|
631
|
+
* }
|
|
632
|
+
*/
|
|
633
|
+
listBans(serverId: string): Promise<BanEntry[]>;
|
|
634
|
+
/**
|
|
635
|
+
* Send a direct message to a user (DM).
|
|
636
|
+
* Requires the `messages.write` scope.
|
|
637
|
+
*
|
|
638
|
+
* @example
|
|
639
|
+
* await client.members.dm('user-id', { content: 'Hello!' })
|
|
640
|
+
* await client.members.dm('user-id', 'Hello from the bot!')
|
|
641
|
+
*/
|
|
642
|
+
dm(userId: string, options: string | Omit<SendMessageOptions, 'replyToId'>): Promise<Message>;
|
|
643
|
+
/**
|
|
644
|
+
* Add a role to a member.
|
|
645
|
+
* Requires the `members.roles` scope.
|
|
646
|
+
*
|
|
647
|
+
* @example
|
|
648
|
+
* await client.members.addRole('server-id', 'user-id', 'role-id')
|
|
649
|
+
*/
|
|
650
|
+
addRole(serverId: string, userId: string, roleId: string): Promise<{
|
|
651
|
+
ok: true;
|
|
652
|
+
}>;
|
|
653
|
+
/**
|
|
654
|
+
* Remove a role from a member.
|
|
655
|
+
* Requires the `members.roles` scope.
|
|
656
|
+
*
|
|
657
|
+
* @example
|
|
658
|
+
* await client.members.removeRole('server-id', 'user-id', 'role-id')
|
|
659
|
+
*/
|
|
660
|
+
removeRole(serverId: string, userId: string, roleId: string): Promise<{
|
|
661
|
+
ok: true;
|
|
662
|
+
}>;
|
|
463
663
|
}
|
|
464
664
|
|
|
465
665
|
declare class ServersAPI {
|
|
@@ -473,6 +673,15 @@ declare class ServersAPI {
|
|
|
473
673
|
* console.log(`Bot is in ${servers.length} servers`)
|
|
474
674
|
*/
|
|
475
675
|
list(): Promise<NovaServer[]>;
|
|
676
|
+
/**
|
|
677
|
+
* Fetch all roles in a server.
|
|
678
|
+
* Results are sorted by position (lowest first).
|
|
679
|
+
*
|
|
680
|
+
* @example
|
|
681
|
+
* const roles = await client.servers.listRoles('server-id')
|
|
682
|
+
* const adminRole = roles.find(r => r.name === 'Admin')
|
|
683
|
+
*/
|
|
684
|
+
listRoles(serverId: string): Promise<Role[]>;
|
|
476
685
|
}
|
|
477
686
|
|
|
478
687
|
declare class InteractionsAPI {
|
|
@@ -598,6 +807,144 @@ declare class PermissionsAPI {
|
|
|
598
807
|
get(options: PermissionsQueryOptions): Promise<PermissionsResult>;
|
|
599
808
|
}
|
|
600
809
|
|
|
810
|
+
declare class ChannelsAPI {
|
|
811
|
+
private readonly http;
|
|
812
|
+
constructor(http: HttpClient);
|
|
813
|
+
/**
|
|
814
|
+
* Fetch all channels in a server the bot is a member of.
|
|
815
|
+
*
|
|
816
|
+
* @example
|
|
817
|
+
* const channels = await client.channels.list('server-id')
|
|
818
|
+
* const textChannels = channels.filter(c => c.type === 'TEXT')
|
|
819
|
+
*/
|
|
820
|
+
list(serverId: string): Promise<Channel[]>;
|
|
821
|
+
/**
|
|
822
|
+
* Fetch a single channel by ID.
|
|
823
|
+
*
|
|
824
|
+
* @example
|
|
825
|
+
* const channel = await client.channels.fetch('channel-id')
|
|
826
|
+
* console.log(channel.name, channel.type)
|
|
827
|
+
*/
|
|
828
|
+
fetch(channelId: string): Promise<Channel>;
|
|
829
|
+
/**
|
|
830
|
+
* Create a new channel in a server.
|
|
831
|
+
* Requires the `channels.manage` scope.
|
|
832
|
+
*
|
|
833
|
+
* @example
|
|
834
|
+
* const channel = await client.channels.create('server-id', {
|
|
835
|
+
* name: 'announcements',
|
|
836
|
+
* type: 'ANNOUNCEMENT',
|
|
837
|
+
* topic: 'Official announcements only',
|
|
838
|
+
* })
|
|
839
|
+
*/
|
|
840
|
+
create(serverId: string, options: CreateChannelOptions): Promise<Channel>;
|
|
841
|
+
/**
|
|
842
|
+
* Edit an existing channel.
|
|
843
|
+
* Requires the `channels.manage` scope.
|
|
844
|
+
*
|
|
845
|
+
* @example
|
|
846
|
+
* await client.channels.edit('channel-id', { topic: 'New topic!' })
|
|
847
|
+
*/
|
|
848
|
+
edit(channelId: string, options: EditChannelOptions): Promise<Channel>;
|
|
849
|
+
/**
|
|
850
|
+
* Delete a channel.
|
|
851
|
+
* Requires the `channels.manage` scope.
|
|
852
|
+
*
|
|
853
|
+
* @example
|
|
854
|
+
* await client.channels.delete('channel-id')
|
|
855
|
+
*/
|
|
856
|
+
delete(channelId: string): Promise<{
|
|
857
|
+
ok: true;
|
|
858
|
+
}>;
|
|
859
|
+
/**
|
|
860
|
+
* Fetch messages from a channel.
|
|
861
|
+
*
|
|
862
|
+
* @example
|
|
863
|
+
* const messages = await client.channels.fetchMessages('channel-id', { limit: 50 })
|
|
864
|
+
*/
|
|
865
|
+
fetchMessages(channelId: string, options?: FetchMessagesOptions): Promise<Message[]>;
|
|
866
|
+
/**
|
|
867
|
+
* Fetch all pinned messages in a channel.
|
|
868
|
+
*
|
|
869
|
+
* @example
|
|
870
|
+
* const pins = await client.channels.fetchPins('channel-id')
|
|
871
|
+
*/
|
|
872
|
+
fetchPins(channelId: string): Promise<Message[]>;
|
|
873
|
+
/**
|
|
874
|
+
* Send a typing indicator in a channel.
|
|
875
|
+
* Displayed to users for ~5 seconds.
|
|
876
|
+
*
|
|
877
|
+
* @example
|
|
878
|
+
* await client.channels.startTyping('channel-id')
|
|
879
|
+
*/
|
|
880
|
+
startTyping(channelId: string): Promise<{
|
|
881
|
+
ok: true;
|
|
882
|
+
}>;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
declare class ReactionsAPI {
|
|
886
|
+
private readonly http;
|
|
887
|
+
constructor(http: HttpClient);
|
|
888
|
+
/**
|
|
889
|
+
* Add a reaction to a message.
|
|
890
|
+
* Use a plain emoji character or a custom emoji ID.
|
|
891
|
+
*
|
|
892
|
+
* @example
|
|
893
|
+
* await client.reactions.add('message-id', '👍')
|
|
894
|
+
* await client.reactions.add('message-id', '🎉')
|
|
895
|
+
*/
|
|
896
|
+
add(messageId: string, emoji: string): Promise<{
|
|
897
|
+
ok: true;
|
|
898
|
+
}>;
|
|
899
|
+
/**
|
|
900
|
+
* Remove the bot's reaction from a message.
|
|
901
|
+
*
|
|
902
|
+
* @example
|
|
903
|
+
* await client.reactions.remove('message-id', '👍')
|
|
904
|
+
*/
|
|
905
|
+
remove(messageId: string, emoji: string): Promise<{
|
|
906
|
+
ok: true;
|
|
907
|
+
}>;
|
|
908
|
+
/**
|
|
909
|
+
* Remove all reactions from a message.
|
|
910
|
+
* Requires the `messages.manage` scope.
|
|
911
|
+
*
|
|
912
|
+
* @example
|
|
913
|
+
* await client.reactions.removeAll('message-id')
|
|
914
|
+
*/
|
|
915
|
+
removeAll(messageId: string): Promise<{
|
|
916
|
+
ok: true;
|
|
917
|
+
}>;
|
|
918
|
+
/**
|
|
919
|
+
* Remove all reactions of a specific emoji from a message.
|
|
920
|
+
* Requires the `messages.manage` scope.
|
|
921
|
+
*
|
|
922
|
+
* @example
|
|
923
|
+
* await client.reactions.removeEmoji('message-id', '👍')
|
|
924
|
+
*/
|
|
925
|
+
removeEmoji(messageId: string, emoji: string): Promise<{
|
|
926
|
+
ok: true;
|
|
927
|
+
}>;
|
|
928
|
+
/**
|
|
929
|
+
* Fetch all reactions on a message, broken down by emoji.
|
|
930
|
+
*
|
|
931
|
+
* @example
|
|
932
|
+
* const reactions = await client.reactions.fetch('message-id')
|
|
933
|
+
* for (const r of reactions) {
|
|
934
|
+
* console.log(`${r.emoji} — ${r.count} reactions from ${r.users.map(u => u.username).join(', ')}`)
|
|
935
|
+
* }
|
|
936
|
+
*/
|
|
937
|
+
fetch(messageId: string): Promise<ReactionDetail[]>;
|
|
938
|
+
/**
|
|
939
|
+
* Fetch reactions for a specific emoji on a message.
|
|
940
|
+
*
|
|
941
|
+
* @example
|
|
942
|
+
* const detail = await client.reactions.fetchEmoji('message-id', '👍')
|
|
943
|
+
* console.log(`${detail.count} thumbs ups`)
|
|
944
|
+
*/
|
|
945
|
+
fetchEmoji(messageId: string, emoji: string): Promise<ReactionDetail>;
|
|
946
|
+
}
|
|
947
|
+
|
|
601
948
|
type TextInputStyle = 'short' | 'paragraph';
|
|
602
949
|
/**
|
|
603
950
|
* Fluent builder for a single text-input field inside a modal.
|
|
@@ -878,284 +1225,792 @@ declare class NovaInteraction {
|
|
|
878
1225
|
toJSON(): Interaction;
|
|
879
1226
|
}
|
|
880
1227
|
|
|
881
|
-
interface NovaClientEvents {
|
|
882
|
-
/** Fired when the bot connects and is identified by the gateway. */
|
|
883
|
-
ready: (bot: BotApplication) => void;
|
|
884
|
-
/** Fired for every raw `bot:event` from the gateway. */
|
|
885
|
-
event: (event: BotEvent) => void;
|
|
886
|
-
/**
|
|
887
|
-
* Fired when an interaction is received (slash command, button click, etc.).
|
|
888
|
-
* Use `client.command()`, `client.button()`, or `client.selectMenu()` for
|
|
889
|
-
* convenient routing instead of handling everything here.
|
|
890
|
-
*/
|
|
891
|
-
interactionCreate: (interaction: NovaInteraction) => void;
|
|
892
|
-
/** Fired when the WebSocket connection drops. */
|
|
893
|
-
disconnect: (reason: string) => void;
|
|
894
|
-
/** Fired on gateway / API errors. */
|
|
895
|
-
error: (err: Error | {
|
|
896
|
-
code: number;
|
|
897
|
-
message: string;
|
|
898
|
-
}) => void;
|
|
899
|
-
/** A new message was sent in a channel the bot can see. */
|
|
900
|
-
messageCreate: (data: BotEvent['data']) => void;
|
|
901
|
-
/** A message was edited. */
|
|
902
|
-
messageUpdate: (data: BotEvent['data']) => void;
|
|
903
|
-
/** A message was deleted. */
|
|
904
|
-
messageDelete: (data: BotEvent['data']) => void;
|
|
905
|
-
/** A reaction was added. */
|
|
906
|
-
reactionAdd: (data: BotEvent['data']) => void;
|
|
907
|
-
/** A reaction was removed. */
|
|
908
|
-
reactionRemove: (data: BotEvent['data']) => void;
|
|
909
|
-
/** A member joined a server the bot is in. */
|
|
910
|
-
memberAdd: (data: BotEvent['data']) => void;
|
|
911
|
-
/** A member left a server the bot is in. */
|
|
912
|
-
memberRemove: (data: BotEvent['data']) => void;
|
|
913
|
-
/** A user started typing. */
|
|
914
|
-
typingStart: (data: BotEvent['data']) => void;
|
|
915
|
-
}
|
|
916
1228
|
/**
|
|
917
|
-
*
|
|
1229
|
+
* A rich wrapper around a raw `Message` with convenience methods.
|
|
918
1230
|
*
|
|
919
|
-
*
|
|
920
|
-
* import { NovaClient } from 'nova-bot-sdk'
|
|
921
|
-
*
|
|
922
|
-
* const client = new NovaClient({ token: 'nova_bot_...' })
|
|
923
|
-
*
|
|
924
|
-
* client.on('ready', (bot) => {
|
|
925
|
-
* console.log(`Logged in as ${bot.botUser.username}`)
|
|
926
|
-
* })
|
|
1231
|
+
* Returned by `client.on('messageCreate', ...)` and from message fetch calls.
|
|
927
1232
|
*
|
|
928
|
-
*
|
|
929
|
-
*
|
|
930
|
-
*
|
|
1233
|
+
* @example
|
|
1234
|
+
* client.on('messageCreate', async (msg) => {
|
|
1235
|
+
* if (msg.content.toLowerCase() === '!ping') {
|
|
1236
|
+
* await msg.reply('Pong! 🏓')
|
|
1237
|
+
* await msg.react('🏓')
|
|
931
1238
|
* }
|
|
932
1239
|
* })
|
|
933
|
-
*
|
|
934
|
-
* await client.connect()
|
|
935
1240
|
*/
|
|
936
|
-
declare class
|
|
937
|
-
/** The
|
|
938
|
-
|
|
939
|
-
/**
|
|
940
|
-
readonly
|
|
941
|
-
/**
|
|
942
|
-
readonly
|
|
943
|
-
/**
|
|
944
|
-
readonly
|
|
945
|
-
/**
|
|
946
|
-
readonly
|
|
947
|
-
/**
|
|
948
|
-
readonly
|
|
949
|
-
/**
|
|
950
|
-
readonly
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1241
|
+
declare class NovaMessage {
|
|
1242
|
+
/** The raw message ID. */
|
|
1243
|
+
readonly id: string;
|
|
1244
|
+
/** The message text content. */
|
|
1245
|
+
readonly content: string;
|
|
1246
|
+
/** The channel this message was sent in. */
|
|
1247
|
+
readonly channelId: string;
|
|
1248
|
+
/** The author of the message. */
|
|
1249
|
+
readonly author: Message['author'];
|
|
1250
|
+
/** Embed attached to this message, if any. */
|
|
1251
|
+
readonly embed: Embed | null;
|
|
1252
|
+
/** Interactive components (buttons, selects) attached to this message. */
|
|
1253
|
+
readonly components: MessageComponent[];
|
|
1254
|
+
/** The message this is replying to, if any. */
|
|
1255
|
+
readonly replyToId: string | null;
|
|
1256
|
+
/** Uploaded file attachments. */
|
|
1257
|
+
readonly attachments: Attachment[];
|
|
1258
|
+
/** Reactions on this message. */
|
|
1259
|
+
readonly reactions: Reaction[];
|
|
1260
|
+
/** When the message was sent. */
|
|
1261
|
+
readonly createdAt: Date;
|
|
1262
|
+
/** When the message was last edited, or `null`. */
|
|
1263
|
+
readonly editedAt: Date | null;
|
|
1264
|
+
private readonly _messages;
|
|
1265
|
+
private readonly _reactions;
|
|
1266
|
+
constructor(raw: Message, messages: MessagesAPI, reactions: ReactionsAPI);
|
|
1267
|
+
/** Returns true if the message was sent by a bot. */
|
|
1268
|
+
isFromBot(): boolean;
|
|
1269
|
+
/** Returns true if the message has an embed. */
|
|
1270
|
+
hasEmbed(): boolean;
|
|
1271
|
+
/** Returns true if the message has interactive components. */
|
|
1272
|
+
hasComponents(): boolean;
|
|
1273
|
+
/** Returns true if the message has been edited. */
|
|
1274
|
+
isEdited(): boolean;
|
|
958
1275
|
/**
|
|
959
|
-
*
|
|
960
|
-
* Automatically routes `interactionCreate` events whose `commandName` matches.
|
|
1276
|
+
* Add a reaction to this message.
|
|
961
1277
|
*
|
|
962
1278
|
* @example
|
|
963
|
-
*
|
|
964
|
-
*
|
|
965
|
-
* })
|
|
1279
|
+
* await msg.react('👍')
|
|
1280
|
+
* await msg.react('🎉')
|
|
966
1281
|
*/
|
|
967
|
-
|
|
1282
|
+
react(emoji: string): Promise<{
|
|
1283
|
+
ok: true;
|
|
1284
|
+
}>;
|
|
968
1285
|
/**
|
|
969
|
-
*
|
|
1286
|
+
* Remove the bot's reaction from this message.
|
|
970
1287
|
*
|
|
971
1288
|
* @example
|
|
972
|
-
*
|
|
973
|
-
* await interaction.replyEphemeral('Deleted.')
|
|
974
|
-
* })
|
|
1289
|
+
* await msg.removeReaction('👍')
|
|
975
1290
|
*/
|
|
976
|
-
|
|
1291
|
+
removeReaction(emoji: string): Promise<{
|
|
1292
|
+
ok: true;
|
|
1293
|
+
}>;
|
|
977
1294
|
/**
|
|
978
|
-
*
|
|
1295
|
+
* Reply to this message.
|
|
979
1296
|
*
|
|
980
1297
|
* @example
|
|
981
|
-
*
|
|
982
|
-
*
|
|
983
|
-
* await interaction.reply(`You picked: ${chosen}`)
|
|
984
|
-
* })
|
|
1298
|
+
* await msg.reply('Got it!')
|
|
1299
|
+
* await msg.reply({ embed: new EmbedBuilder().setTitle('Result').toJSON() })
|
|
985
1300
|
*/
|
|
986
|
-
|
|
1301
|
+
reply(options: string | Omit<SendMessageOptions, 'replyToId'>): Promise<NovaMessage>;
|
|
987
1302
|
/**
|
|
988
|
-
*
|
|
989
|
-
*
|
|
1303
|
+
* Edit this message.
|
|
1304
|
+
* Only works if the bot is the author.
|
|
990
1305
|
*
|
|
991
1306
|
* @example
|
|
992
|
-
* await
|
|
1307
|
+
* await msg.edit('Updated content')
|
|
1308
|
+
* await msg.edit({ content: 'Updated', embed: { title: 'New embed' } })
|
|
993
1309
|
*/
|
|
994
|
-
|
|
1310
|
+
edit(options: string | EditMessageOptions): Promise<NovaMessage>;
|
|
995
1311
|
/**
|
|
996
|
-
*
|
|
1312
|
+
* Delete this message.
|
|
1313
|
+
* Only works if the bot is the author.
|
|
1314
|
+
*
|
|
1315
|
+
* @example
|
|
1316
|
+
* await msg.delete()
|
|
997
1317
|
*/
|
|
998
|
-
|
|
1318
|
+
delete(): Promise<{
|
|
1319
|
+
ok: true;
|
|
1320
|
+
}>;
|
|
999
1321
|
/**
|
|
1000
|
-
*
|
|
1001
|
-
* Requires the `messages.write` scope.
|
|
1322
|
+
* Pin this message in its channel.
|
|
1002
1323
|
*
|
|
1003
1324
|
* @example
|
|
1004
|
-
*
|
|
1325
|
+
* await msg.pin()
|
|
1005
1326
|
*/
|
|
1006
|
-
|
|
1327
|
+
pin(): Promise<{
|
|
1328
|
+
ok: true;
|
|
1329
|
+
}>;
|
|
1007
1330
|
/**
|
|
1008
|
-
*
|
|
1331
|
+
* Unpin this message.
|
|
1332
|
+
*
|
|
1333
|
+
* @example
|
|
1334
|
+
* await msg.unpin()
|
|
1009
1335
|
*/
|
|
1010
|
-
|
|
1336
|
+
unpin(): Promise<{
|
|
1337
|
+
ok: true;
|
|
1338
|
+
}>;
|
|
1011
1339
|
/**
|
|
1012
|
-
*
|
|
1340
|
+
* Re-fetch the latest version of this message from the server.
|
|
1341
|
+
*
|
|
1342
|
+
* @example
|
|
1343
|
+
* const fresh = await msg.fetch()
|
|
1013
1344
|
*/
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1345
|
+
fetch(): Promise<NovaMessage>;
|
|
1346
|
+
/**
|
|
1347
|
+
* Get a URL to this message (deep link).
|
|
1348
|
+
*/
|
|
1349
|
+
get url(): string;
|
|
1350
|
+
/**
|
|
1351
|
+
* Return the raw message object.
|
|
1352
|
+
*/
|
|
1353
|
+
toJSON(): Message;
|
|
1354
|
+
toString(): string;
|
|
1023
1355
|
}
|
|
1024
1356
|
|
|
1025
1357
|
/**
|
|
1026
|
-
*
|
|
1358
|
+
* A rich wrapper around a raw `Channel` with convenience methods.
|
|
1359
|
+
*
|
|
1360
|
+
* Returned by `client.fetchChannel()` and `client.fetchChannels()`.
|
|
1027
1361
|
*
|
|
1028
1362
|
* @example
|
|
1029
|
-
* const
|
|
1030
|
-
* .setTitle('Server Stats')
|
|
1031
|
-
* .setDescription('Here are the latest numbers.')
|
|
1032
|
-
* .setColor('#5865F2')
|
|
1033
|
-
* .addField('Members', '1 234', true)
|
|
1034
|
-
* .addField('Messages today', '567', true)
|
|
1035
|
-
* .setFooter('Nova Bot')
|
|
1036
|
-
* .setTimestamp()
|
|
1363
|
+
* const channel = await client.fetchChannel('channel-id')
|
|
1037
1364
|
*
|
|
1038
|
-
* await
|
|
1365
|
+
* await channel.send('Hello from the bot!')
|
|
1366
|
+
* await channel.edit({ topic: 'New topic' })
|
|
1367
|
+
* const messages = await channel.fetchMessages({ limit: 20 })
|
|
1039
1368
|
*/
|
|
1040
|
-
declare class
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1369
|
+
declare class NovaChannel {
|
|
1370
|
+
/** The channel's unique ID. */
|
|
1371
|
+
readonly id: string;
|
|
1372
|
+
/** The channel's name (without #). */
|
|
1373
|
+
readonly name: string;
|
|
1374
|
+
/** The channel type — `'TEXT'`, `'VOICE'`, `'ANNOUNCEMENT'`, `'FORUM'`, or `'STAGE'`. */
|
|
1375
|
+
readonly type: ChannelType;
|
|
1376
|
+
/** The ID of the server this channel belongs to. */
|
|
1377
|
+
readonly serverId: string | null;
|
|
1378
|
+
/** Optional topic / description text. */
|
|
1379
|
+
readonly topic: string | null;
|
|
1380
|
+
/** Sorting position (lower = higher in the list). */
|
|
1381
|
+
readonly position: number;
|
|
1382
|
+
/** Slow-mode interval in seconds (`0` = disabled). */
|
|
1383
|
+
readonly slowMode: number;
|
|
1384
|
+
/** When the channel was created. */
|
|
1385
|
+
readonly createdAt: Date;
|
|
1386
|
+
private readonly _channels;
|
|
1387
|
+
private readonly _messages;
|
|
1388
|
+
constructor(raw: Channel, channels: ChannelsAPI, messages: MessagesAPI);
|
|
1389
|
+
/** `true` for text channels. */
|
|
1390
|
+
isText(): boolean;
|
|
1391
|
+
/** `true` for voice channels. */
|
|
1392
|
+
isVoice(): boolean;
|
|
1393
|
+
/** `true` for announcement channels. */
|
|
1394
|
+
isAnnouncement(): boolean;
|
|
1395
|
+
/** `true` for forum channels. */
|
|
1396
|
+
isForum(): boolean;
|
|
1397
|
+
/** `true` for stage channels. */
|
|
1398
|
+
isStage(): boolean;
|
|
1399
|
+
/** `true` if slow-mode is enabled on this channel. */
|
|
1400
|
+
hasSlowMode(): boolean;
|
|
1046
1401
|
/**
|
|
1047
|
-
*
|
|
1048
|
-
*
|
|
1402
|
+
* Send a message to this channel.
|
|
1403
|
+
* Accepts a plain string or a full options object.
|
|
1404
|
+
*
|
|
1405
|
+
* @example
|
|
1406
|
+
* await channel.send('Hello!')
|
|
1407
|
+
* await channel.send({ content: 'Hi', embed: { title: 'Stats' } })
|
|
1049
1408
|
*/
|
|
1050
|
-
|
|
1051
|
-
/** Make the title a clickable hyperlink. */
|
|
1052
|
-
setUrl(url: string): this;
|
|
1053
|
-
/** Small image shown in the top-right corner. */
|
|
1054
|
-
setThumbnail(url: string): this;
|
|
1055
|
-
/** Large image shown below the fields. */
|
|
1056
|
-
setImage(url: string): this;
|
|
1057
|
-
/** Footer text shown at the very bottom of the embed. */
|
|
1058
|
-
setFooter(text: string): this;
|
|
1409
|
+
send(options: string | SendMessageOptions): Promise<Message>;
|
|
1059
1410
|
/**
|
|
1060
|
-
*
|
|
1061
|
-
*
|
|
1411
|
+
* Fetch recent messages from this channel.
|
|
1412
|
+
*
|
|
1413
|
+
* @example
|
|
1414
|
+
* const messages = await channel.fetchMessages({ limit: 50 })
|
|
1062
1415
|
*/
|
|
1063
|
-
|
|
1064
|
-
/** Author name + optional icon shown above the title. */
|
|
1065
|
-
setAuthor(author: {
|
|
1066
|
-
name: string;
|
|
1067
|
-
iconUrl?: string;
|
|
1068
|
-
}): this;
|
|
1416
|
+
fetchMessages(options?: FetchMessagesOptions): Promise<Message[]>;
|
|
1069
1417
|
/**
|
|
1070
|
-
*
|
|
1071
|
-
*
|
|
1418
|
+
* Fetch all pinned messages in this channel.
|
|
1419
|
+
*
|
|
1420
|
+
* @example
|
|
1421
|
+
* const pins = await channel.fetchPins()
|
|
1072
1422
|
*/
|
|
1073
|
-
|
|
1074
|
-
/**
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1423
|
+
fetchPins(): Promise<Message[]>;
|
|
1424
|
+
/**
|
|
1425
|
+
* Start a typing indicator (shows "Bot is typing…" for ~5 seconds).
|
|
1426
|
+
*
|
|
1427
|
+
* @example
|
|
1428
|
+
* await channel.startTyping()
|
|
1429
|
+
*/
|
|
1430
|
+
startTyping(): Promise<{
|
|
1431
|
+
ok: true;
|
|
1432
|
+
}>;
|
|
1433
|
+
/**
|
|
1434
|
+
* Edit this channel's properties.
|
|
1435
|
+
* Requires the `channels.manage` scope.
|
|
1436
|
+
*
|
|
1437
|
+
* @example
|
|
1438
|
+
* await channel.edit({ name: 'general-2', topic: 'The second general channel' })
|
|
1439
|
+
*/
|
|
1440
|
+
edit(options: EditChannelOptions): Promise<NovaChannel>;
|
|
1441
|
+
/**
|
|
1442
|
+
* Delete this channel.
|
|
1443
|
+
* Requires the `channels.manage` scope.
|
|
1444
|
+
*
|
|
1445
|
+
* @example
|
|
1446
|
+
* await channel.delete()
|
|
1447
|
+
*/
|
|
1448
|
+
delete(): Promise<{
|
|
1449
|
+
ok: true;
|
|
1450
|
+
}>;
|
|
1451
|
+
/**
|
|
1452
|
+
* Returns the channel as a mention-style string: `#name`.
|
|
1453
|
+
*/
|
|
1454
|
+
toString(): string;
|
|
1455
|
+
/** Returns the raw channel data. */
|
|
1456
|
+
toJSON(): Channel;
|
|
1080
1457
|
}
|
|
1081
1458
|
|
|
1082
|
-
type ButtonStyle = 'primary' | 'secondary' | 'success' | 'danger' | 'link';
|
|
1083
1459
|
/**
|
|
1084
|
-
*
|
|
1460
|
+
* A rich wrapper around a raw `Member` with convenience methods.
|
|
1461
|
+
*
|
|
1462
|
+
* Returned by `client.fetchMember()` and `client.fetchMembers()`.
|
|
1085
1463
|
*
|
|
1086
1464
|
* @example
|
|
1087
|
-
* const
|
|
1088
|
-
* .addButton(
|
|
1089
|
-
* new ButtonBuilder()
|
|
1090
|
-
* .setCustomId('confirm')
|
|
1091
|
-
* .setLabel('Confirm')
|
|
1092
|
-
* .setStyle('success')
|
|
1093
|
-
* )
|
|
1094
|
-
* .addButton(
|
|
1095
|
-
* new ButtonBuilder()
|
|
1096
|
-
* .setCustomId('cancel')
|
|
1097
|
-
* .setLabel('Cancel')
|
|
1098
|
-
* .setStyle('danger')
|
|
1099
|
-
* )
|
|
1465
|
+
* const member = await client.fetchMember('server-id', 'user-id')
|
|
1100
1466
|
*
|
|
1101
|
-
*
|
|
1467
|
+
* if (member.isAdmin()) {
|
|
1468
|
+
* await member.dm('You have admin access.')
|
|
1469
|
+
* } else {
|
|
1470
|
+
* await member.kick()
|
|
1471
|
+
* }
|
|
1102
1472
|
*/
|
|
1103
|
-
declare class
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
/**
|
|
1111
|
-
|
|
1112
|
-
/**
|
|
1113
|
-
|
|
1473
|
+
declare class NovaMember {
|
|
1474
|
+
/** The user's unique ID. */
|
|
1475
|
+
readonly userId: string;
|
|
1476
|
+
/** The server this membership belongs to. */
|
|
1477
|
+
readonly serverId: string;
|
|
1478
|
+
/** The user's username (login handle). */
|
|
1479
|
+
readonly username: string;
|
|
1480
|
+
/** The user's display name. */
|
|
1481
|
+
readonly displayName: string;
|
|
1482
|
+
/** URL of the user's avatar, or `null`. */
|
|
1483
|
+
readonly avatar: string | null;
|
|
1484
|
+
/** The member's server role — `'OWNER'`, `'ADMIN'`, or `'MEMBER'`. */
|
|
1485
|
+
readonly role: 'OWNER' | 'ADMIN' | 'MEMBER';
|
|
1486
|
+
/** The user's current presence status. */
|
|
1487
|
+
readonly status: 'ONLINE' | 'IDLE' | 'DND' | 'OFFLINE';
|
|
1488
|
+
/** `true` if this member is a bot account. */
|
|
1489
|
+
readonly isBot: boolean;
|
|
1490
|
+
/** When this user joined the server. */
|
|
1491
|
+
readonly joinedAt: Date;
|
|
1492
|
+
private readonly _members;
|
|
1493
|
+
constructor(raw: Member, serverId: string, members: MembersAPI);
|
|
1494
|
+
/** `true` if this member is the server owner. */
|
|
1495
|
+
isOwner(): boolean;
|
|
1496
|
+
/** `true` if this member is an admin or the server owner. */
|
|
1497
|
+
isAdmin(): boolean;
|
|
1498
|
+
/** `true` if this member is a regular (non-privileged) member. */
|
|
1499
|
+
isRegularMember(): boolean;
|
|
1500
|
+
/** `true` if the user is currently online. */
|
|
1501
|
+
isOnline(): boolean;
|
|
1502
|
+
/** `true` if the user is idle / away. */
|
|
1503
|
+
isIdle(): boolean;
|
|
1504
|
+
/** `true` if the user is set to Do Not Disturb. */
|
|
1505
|
+
isDND(): boolean;
|
|
1506
|
+
/** `true` if the user appears offline. */
|
|
1507
|
+
isOffline(): boolean;
|
|
1114
1508
|
/**
|
|
1115
|
-
*
|
|
1116
|
-
*
|
|
1117
|
-
*
|
|
1118
|
-
*
|
|
1119
|
-
*
|
|
1120
|
-
* - `link` — grey, navigates to a URL instead of creating an interaction
|
|
1509
|
+
* Kick this member from the server.
|
|
1510
|
+
* Bots cannot kick owners or admins (throws 403).
|
|
1511
|
+
*
|
|
1512
|
+
* @example
|
|
1513
|
+
* await member.kick()
|
|
1121
1514
|
*/
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1515
|
+
kick(): Promise<{
|
|
1516
|
+
ok: true;
|
|
1517
|
+
}>;
|
|
1125
1518
|
/**
|
|
1126
|
-
*
|
|
1127
|
-
*
|
|
1519
|
+
* Ban this member from the server with an optional reason.
|
|
1520
|
+
* Bots cannot ban owners or admins (throws 403).
|
|
1521
|
+
*
|
|
1522
|
+
* @example
|
|
1523
|
+
* await member.ban('Repeated rule violations')
|
|
1128
1524
|
*/
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1525
|
+
ban(reason?: string): Promise<{
|
|
1526
|
+
ok: true;
|
|
1527
|
+
}>;
|
|
1528
|
+
/**
|
|
1529
|
+
* Send this user a direct message.
|
|
1530
|
+
* Requires the `messages.write` scope.
|
|
1531
|
+
*
|
|
1532
|
+
* @example
|
|
1533
|
+
* await member.dm('Welcome to the server!')
|
|
1534
|
+
* await member.dm({ content: 'Hello', embed: { title: 'Rules' } })
|
|
1535
|
+
*/
|
|
1536
|
+
dm(options: string | Omit<SendMessageOptions, 'replyToId'>): Promise<Message>;
|
|
1537
|
+
/**
|
|
1538
|
+
* Assign a custom role to this member.
|
|
1539
|
+
* Requires the `members.roles` scope.
|
|
1540
|
+
*
|
|
1541
|
+
* @example
|
|
1542
|
+
* await member.addRole('role-id')
|
|
1543
|
+
*/
|
|
1544
|
+
addRole(roleId: string): Promise<{
|
|
1545
|
+
ok: true;
|
|
1546
|
+
}>;
|
|
1547
|
+
/**
|
|
1548
|
+
* Remove a custom role from this member.
|
|
1549
|
+
* Requires the `members.roles` scope.
|
|
1550
|
+
*
|
|
1551
|
+
* @example
|
|
1552
|
+
* await member.removeRole('role-id')
|
|
1553
|
+
*/
|
|
1554
|
+
removeRole(roleId: string): Promise<{
|
|
1555
|
+
ok: true;
|
|
1556
|
+
}>;
|
|
1557
|
+
/**
|
|
1558
|
+
* Returns a mention-style string: `@displayName`.
|
|
1559
|
+
*/
|
|
1560
|
+
toString(): string;
|
|
1561
|
+
/** Returns the raw member data. */
|
|
1562
|
+
toJSON(): Member;
|
|
1133
1563
|
}
|
|
1134
1564
|
|
|
1135
|
-
interface
|
|
1136
|
-
/**
|
|
1137
|
-
|
|
1138
|
-
/**
|
|
1139
|
-
|
|
1140
|
-
/**
|
|
1141
|
-
|
|
1565
|
+
interface NovaClientEvents {
|
|
1566
|
+
/** Fired when the bot connects and is identified by the gateway. */
|
|
1567
|
+
ready: (bot: BotApplication) => void;
|
|
1568
|
+
/** Fired for every raw `bot:event` from the gateway. */
|
|
1569
|
+
event: (event: BotEvent) => void;
|
|
1570
|
+
/**
|
|
1571
|
+
* Fired when an interaction is received (slash command, button click, etc.).
|
|
1572
|
+
* Use `client.command()`, `client.button()`, or `client.selectMenu()` for
|
|
1573
|
+
* convenient routing instead of handling everything here.
|
|
1574
|
+
*/
|
|
1575
|
+
interactionCreate: (interaction: NovaInteraction) => void;
|
|
1576
|
+
/** Fired when the WebSocket connection drops. */
|
|
1577
|
+
disconnect: (reason: string) => void;
|
|
1578
|
+
/** Fired on gateway / API errors. */
|
|
1579
|
+
error: (err: Error | {
|
|
1580
|
+
code: number;
|
|
1581
|
+
message: string;
|
|
1582
|
+
}) => void;
|
|
1583
|
+
/** A new message was sent in a channel the bot can see. */
|
|
1584
|
+
messageCreate: (message: NovaMessage) => void;
|
|
1585
|
+
/** A message was edited. Returns the updated message. */
|
|
1586
|
+
messageUpdate: (message: NovaMessage) => void;
|
|
1587
|
+
/** A message was deleted. Returns partial data. */
|
|
1588
|
+
messageDelete: (data: {
|
|
1589
|
+
id: string;
|
|
1590
|
+
channelId: string;
|
|
1591
|
+
}) => void;
|
|
1592
|
+
/** A reaction was added to a message. */
|
|
1593
|
+
reactionAdd: (data: {
|
|
1594
|
+
messageId: string;
|
|
1595
|
+
channelId: string;
|
|
1596
|
+
userId: string;
|
|
1597
|
+
emoji: string;
|
|
1598
|
+
}) => void;
|
|
1599
|
+
/** A reaction was removed from a message. */
|
|
1600
|
+
reactionRemove: (data: {
|
|
1601
|
+
messageId: string;
|
|
1602
|
+
channelId: string;
|
|
1603
|
+
userId: string;
|
|
1604
|
+
emoji: string;
|
|
1605
|
+
}) => void;
|
|
1606
|
+
/** A member joined a server the bot is in. */
|
|
1607
|
+
memberAdd: (data: {
|
|
1608
|
+
serverId: string;
|
|
1609
|
+
userId: string;
|
|
1610
|
+
username: string;
|
|
1611
|
+
}) => void;
|
|
1612
|
+
/** A member left a server the bot is in. */
|
|
1613
|
+
memberRemove: (data: {
|
|
1614
|
+
serverId: string;
|
|
1615
|
+
userId: string;
|
|
1616
|
+
}) => void;
|
|
1617
|
+
/** A user started typing in a channel. */
|
|
1618
|
+
typingStart: (data: {
|
|
1619
|
+
channelId: string;
|
|
1620
|
+
userId: string;
|
|
1621
|
+
}) => void;
|
|
1622
|
+
/** A message was pinned. */
|
|
1623
|
+
messagePinned: (data: {
|
|
1624
|
+
messageId: string;
|
|
1625
|
+
channelId: string;
|
|
1626
|
+
pinnedBy: string;
|
|
1627
|
+
}) => void;
|
|
1628
|
+
/** A channel was created in a server. */
|
|
1629
|
+
channelCreate: (channel: Channel) => void;
|
|
1630
|
+
/** A channel was updated. */
|
|
1631
|
+
channelUpdate: (channel: Channel) => void;
|
|
1632
|
+
/** A channel was deleted. */
|
|
1633
|
+
channelDelete: (data: {
|
|
1634
|
+
id: string;
|
|
1635
|
+
serverId: string;
|
|
1636
|
+
}) => void;
|
|
1637
|
+
/** A role was created in a server. */
|
|
1638
|
+
roleCreate: (data: {
|
|
1639
|
+
id: string;
|
|
1640
|
+
name: string;
|
|
1641
|
+
color: string | null;
|
|
1642
|
+
serverId: string;
|
|
1643
|
+
position: number;
|
|
1644
|
+
hoist: boolean;
|
|
1645
|
+
createdAt: string;
|
|
1646
|
+
}) => void;
|
|
1647
|
+
/** A role was deleted. */
|
|
1648
|
+
roleDelete: (data: {
|
|
1649
|
+
id: string;
|
|
1650
|
+
serverId: string;
|
|
1651
|
+
}) => void;
|
|
1652
|
+
/** A user joined a voice channel. */
|
|
1653
|
+
voiceJoin: (data: {
|
|
1654
|
+
userId: string;
|
|
1655
|
+
channelId: string;
|
|
1656
|
+
serverId: string;
|
|
1657
|
+
}) => void;
|
|
1658
|
+
/** A user left a voice channel. */
|
|
1659
|
+
voiceLeave: (data: {
|
|
1660
|
+
userId: string;
|
|
1661
|
+
channelId: string;
|
|
1662
|
+
serverId: string;
|
|
1663
|
+
}) => void;
|
|
1664
|
+
/** A member was banned from a server. */
|
|
1665
|
+
memberBanned: (data: {
|
|
1666
|
+
userId: string;
|
|
1667
|
+
serverId: string;
|
|
1668
|
+
moderatorId: string | null;
|
|
1669
|
+
reason: string | null;
|
|
1670
|
+
}) => void;
|
|
1671
|
+
/** A member was unbanned. */
|
|
1672
|
+
memberUnbanned: (data: {
|
|
1673
|
+
userId: string;
|
|
1674
|
+
serverId: string;
|
|
1675
|
+
}) => void;
|
|
1676
|
+
/** A member's profile data was updated. */
|
|
1677
|
+
memberUpdate: (data: {
|
|
1678
|
+
userId: string;
|
|
1679
|
+
serverId: string;
|
|
1680
|
+
}) => void;
|
|
1142
1681
|
}
|
|
1143
1682
|
/**
|
|
1144
|
-
*
|
|
1683
|
+
* The main Nova bot client.
|
|
1145
1684
|
*
|
|
1146
1685
|
* @example
|
|
1147
|
-
*
|
|
1148
|
-
* .setCustomId('colour_pick')
|
|
1149
|
-
* .setPlaceholder('Pick a colour…')
|
|
1150
|
-
* .addOption({ label: 'Red', value: 'red' })
|
|
1151
|
-
* .addOption({ label: 'Green', value: 'green' })
|
|
1152
|
-
* .addOption({ label: 'Blue', value: 'blue' })
|
|
1686
|
+
* import { NovaClient } from 'nova-bot-sdk'
|
|
1153
1687
|
*
|
|
1154
|
-
*
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1688
|
+
* const client = new NovaClient({ token: 'nova_bot_...' })
|
|
1689
|
+
*
|
|
1690
|
+
* client.on('ready', (bot) => {
|
|
1691
|
+
* console.log(`Logged in as ${bot.botUser.username}`)
|
|
1692
|
+
* })
|
|
1693
|
+
*
|
|
1694
|
+
* client.on('interactionCreate', async (interaction) => {
|
|
1695
|
+
* if (interaction.commandName === 'ping') {
|
|
1696
|
+
* await client.interactions.respond(interaction.id, { content: 'Pong!' })
|
|
1697
|
+
* }
|
|
1698
|
+
* })
|
|
1699
|
+
*
|
|
1700
|
+
* await client.connect()
|
|
1701
|
+
*/
|
|
1702
|
+
declare class NovaClient extends EventEmitter {
|
|
1703
|
+
/** The authenticated bot application. Available after `ready` fires. */
|
|
1704
|
+
botUser: BotApplication | null;
|
|
1705
|
+
/** Send, edit, delete and fetch messages. */
|
|
1706
|
+
readonly messages: MessagesAPI;
|
|
1707
|
+
/** Register and manage slash, prefix, and context menu commands. */
|
|
1708
|
+
readonly commands: CommandsAPI;
|
|
1709
|
+
/** List, kick and ban server members. */
|
|
1710
|
+
readonly members: MembersAPI;
|
|
1711
|
+
/** List servers the bot is a member of. */
|
|
1712
|
+
readonly servers: ServersAPI;
|
|
1713
|
+
/** Acknowledge and respond to interactions. */
|
|
1714
|
+
readonly interactions: InteractionsAPI;
|
|
1715
|
+
/** Query the bot's effective permissions within a server, channel, or role scope. */
|
|
1716
|
+
readonly permissions: PermissionsAPI;
|
|
1717
|
+
/** Create, edit, and delete channels; fetch pins and messages. */
|
|
1718
|
+
readonly channels: ChannelsAPI;
|
|
1719
|
+
/** Add, remove and fetch reactions on messages. */
|
|
1720
|
+
readonly reactions: ReactionsAPI;
|
|
1721
|
+
private socket;
|
|
1722
|
+
private readonly http;
|
|
1723
|
+
private readonly options;
|
|
1724
|
+
private _cronTimers;
|
|
1725
|
+
private readonly _commandHandlers;
|
|
1726
|
+
private readonly _buttonHandlers;
|
|
1727
|
+
private readonly _selectHandlers;
|
|
1728
|
+
private readonly _modalHandlers;
|
|
1729
|
+
constructor(options: NovaClientOptions);
|
|
1730
|
+
/**
|
|
1731
|
+
* Register a handler for a slash or prefix command by name.
|
|
1732
|
+
* Automatically routes `interactionCreate` events whose `commandName` matches.
|
|
1733
|
+
*
|
|
1734
|
+
* @example
|
|
1735
|
+
* client.command('ping', async (interaction) => {
|
|
1736
|
+
* await interaction.reply('Pong! 🏓')
|
|
1737
|
+
* })
|
|
1738
|
+
*/
|
|
1739
|
+
command(name: string, handler: (interaction: NovaInteraction) => unknown): this;
|
|
1740
|
+
/**
|
|
1741
|
+
* Register a handler for a button by its `customId`.
|
|
1742
|
+
*
|
|
1743
|
+
* @example
|
|
1744
|
+
* client.button('confirm_delete', async (interaction) => {
|
|
1745
|
+
* await interaction.replyEphemeral('Deleted.')
|
|
1746
|
+
* })
|
|
1747
|
+
*/
|
|
1748
|
+
button(customId: string, handler: (interaction: NovaInteraction) => unknown): this;
|
|
1749
|
+
/**
|
|
1750
|
+
* Register a handler for a select menu by its `customId`.
|
|
1751
|
+
*
|
|
1752
|
+
* @example
|
|
1753
|
+
* client.selectMenu('colour_pick', async (interaction) => {
|
|
1754
|
+
* const chosen = interaction.values[0]
|
|
1755
|
+
* await interaction.reply(`You picked: ${chosen}`)
|
|
1756
|
+
* })
|
|
1757
|
+
*/
|
|
1758
|
+
selectMenu(customId: string, handler: (interaction: NovaInteraction) => unknown): this;
|
|
1759
|
+
/**
|
|
1760
|
+
* Register a handler for a modal submission by its `customId`.
|
|
1761
|
+
* Called automatically when the user submits a modal with that `customId`.
|
|
1762
|
+
*
|
|
1763
|
+
* @example
|
|
1764
|
+
* client.modal('report_modal', async (interaction) => {
|
|
1765
|
+
* const reason = interaction.modalData.reason
|
|
1766
|
+
* await interaction.replyEphemeral(`Report received: ${reason}`)
|
|
1767
|
+
* })
|
|
1768
|
+
*/
|
|
1769
|
+
modal(customId: string, handler: (interaction: NovaInteraction) => unknown): this;
|
|
1770
|
+
/**
|
|
1771
|
+
* Connect to the Nova WebSocket gateway.
|
|
1772
|
+
* Resolves when the `ready` event is received.
|
|
1773
|
+
*
|
|
1774
|
+
* @example
|
|
1775
|
+
* await client.connect()
|
|
1776
|
+
*/
|
|
1777
|
+
connect(): Promise<void>;
|
|
1778
|
+
/**
|
|
1779
|
+
* Register a recurring task that fires at a set interval.
|
|
1780
|
+
* All cron tasks are automatically cancelled on `disconnect()`.
|
|
1781
|
+
*
|
|
1782
|
+
* @param intervalMs - How often to run the task (in milliseconds).
|
|
1783
|
+
* @param fn - Async or sync function to call on each tick.
|
|
1784
|
+
* @returns A cancel function — call it to stop this specific task.
|
|
1785
|
+
*
|
|
1786
|
+
* @example
|
|
1787
|
+
* // Check for new announcements every 30 seconds
|
|
1788
|
+
* client.cron(30_000, async () => {
|
|
1789
|
+
* const messages = await client.messages.fetch(channelId, { limit: 5 })
|
|
1790
|
+
* // do something...
|
|
1791
|
+
* })
|
|
1792
|
+
*/
|
|
1793
|
+
cron(intervalMs: number, fn: () => unknown): () => void;
|
|
1794
|
+
/**
|
|
1795
|
+
* Set the bot's presence status.
|
|
1796
|
+
* Broadcasts to all servers the bot is in via WebSocket.
|
|
1797
|
+
*
|
|
1798
|
+
* @example
|
|
1799
|
+
* client.setStatus('DND') // Do Not Disturb
|
|
1800
|
+
* client.setStatus('IDLE') // Away
|
|
1801
|
+
* client.setStatus('OFFLINE') // Appear offline
|
|
1802
|
+
* client.setStatus('ONLINE') // Back online
|
|
1803
|
+
*/
|
|
1804
|
+
setStatus(status: BotStatus): void;
|
|
1805
|
+
/**
|
|
1806
|
+
* Fetch a single channel and return it as a rich `NovaChannel` wrapper.
|
|
1807
|
+
*
|
|
1808
|
+
* @example
|
|
1809
|
+
* const channel = await client.fetchChannel('channel-id')
|
|
1810
|
+
* await channel.send('Hello!')
|
|
1811
|
+
*/
|
|
1812
|
+
fetchChannel(channelId: string): Promise<NovaChannel>;
|
|
1813
|
+
/**
|
|
1814
|
+
* Fetch all channels in a server and return them as `NovaChannel` wrappers.
|
|
1815
|
+
*
|
|
1816
|
+
* @example
|
|
1817
|
+
* const channels = await client.fetchChannels('server-id')
|
|
1818
|
+
* const textChannels = channels.filter(c => c.isText())
|
|
1819
|
+
*/
|
|
1820
|
+
fetchChannels(serverId: string): Promise<NovaChannel[]>;
|
|
1821
|
+
/**
|
|
1822
|
+
* Fetch all members in a server and return them as `NovaMember` wrappers.
|
|
1823
|
+
*
|
|
1824
|
+
* @example
|
|
1825
|
+
* const members = await client.fetchMembers('server-id')
|
|
1826
|
+
* const bots = members.filter(m => m.isBot)
|
|
1827
|
+
*/
|
|
1828
|
+
fetchMembers(serverId: string): Promise<NovaMember[]>;
|
|
1829
|
+
/**
|
|
1830
|
+
* Fetch a single member from a server and return them as a `NovaMember` wrapper.
|
|
1831
|
+
* Throws if the user is not found in the server.
|
|
1832
|
+
*
|
|
1833
|
+
* @example
|
|
1834
|
+
* const member = await client.fetchMember('server-id', 'user-id')
|
|
1835
|
+
* await member.dm('Welcome!')
|
|
1836
|
+
*/
|
|
1837
|
+
fetchMember(serverId: string, userId: string): Promise<NovaMember>;
|
|
1838
|
+
/**
|
|
1839
|
+
* Wait for a specific event to be emitted, optionally filtered.
|
|
1840
|
+
* Rejects after `timeoutMs` (default 30 s) if the condition never fires.
|
|
1841
|
+
*
|
|
1842
|
+
* @example
|
|
1843
|
+
* // Wait for any message in a specific channel
|
|
1844
|
+
* const msg = await client.waitFor('messageCreate', m => m.channelId === channelId)
|
|
1845
|
+
*
|
|
1846
|
+
* // Wait for a button click with a timeout
|
|
1847
|
+
* const i = await client.waitFor('interactionCreate', i => i.isButton(), 60_000)
|
|
1848
|
+
*/
|
|
1849
|
+
waitFor<K extends keyof NovaClientEvents>(event: K, filter?: (...args: Parameters<NovaClientEvents[K]>) => boolean, timeoutMs?: number): Promise<Parameters<NovaClientEvents[K]>[0]>;
|
|
1850
|
+
/**
|
|
1851
|
+
* Disconnect from the gateway and clean up.
|
|
1852
|
+
*/
|
|
1853
|
+
disconnect(): void;
|
|
1854
|
+
/**
|
|
1855
|
+
* Send a message via the WebSocket gateway (lower latency than HTTP).
|
|
1856
|
+
* Requires the `messages.write` scope.
|
|
1857
|
+
*
|
|
1858
|
+
* @example
|
|
1859
|
+
* client.wsSend('channel-id', 'Hello from the gateway!')
|
|
1860
|
+
*/
|
|
1861
|
+
wsSend(channelId: string, content: string): void;
|
|
1862
|
+
/**
|
|
1863
|
+
* Start a typing indicator via WebSocket.
|
|
1864
|
+
*/
|
|
1865
|
+
wsTypingStart(channelId: string): void;
|
|
1866
|
+
/**
|
|
1867
|
+
* Stop a typing indicator via WebSocket.
|
|
1868
|
+
*/
|
|
1869
|
+
wsTypingStop(channelId: string): void;
|
|
1870
|
+
on<K extends keyof NovaClientEvents>(event: K, listener: NovaClientEvents[K]): this;
|
|
1871
|
+
on(event: string | symbol, listener: (...args: unknown[]) => void): this;
|
|
1872
|
+
once<K extends keyof NovaClientEvents>(event: K, listener: NovaClientEvents[K]): this;
|
|
1873
|
+
once(event: string | symbol, listener: (...args: unknown[]) => void): this;
|
|
1874
|
+
off<K extends keyof NovaClientEvents>(event: K, listener: NovaClientEvents[K]): this;
|
|
1875
|
+
off(event: string | symbol, listener: (...args: unknown[]) => void): this;
|
|
1876
|
+
emit<K extends keyof NovaClientEvents>(event: K, ...args: Parameters<NovaClientEvents[K]>): boolean;
|
|
1877
|
+
emit(event: string | symbol, ...args: unknown[]): boolean;
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
/**
|
|
1881
|
+
* Fluent builder for bot message embeds.
|
|
1882
|
+
*
|
|
1883
|
+
* @example
|
|
1884
|
+
* const embed = new EmbedBuilder()
|
|
1885
|
+
* .setTitle('Server Stats')
|
|
1886
|
+
* .setDescription('Here are the latest numbers.')
|
|
1887
|
+
* .setColor('#5865F2')
|
|
1888
|
+
* .addField('Members', '1 234', true)
|
|
1889
|
+
* .addField('Messages today', '567', true)
|
|
1890
|
+
* .setFooter('Nova Bot')
|
|
1891
|
+
* .setTimestamp()
|
|
1892
|
+
*
|
|
1893
|
+
* await client.messages.send(channelId, { embed })
|
|
1894
|
+
*/
|
|
1895
|
+
declare class EmbedBuilder {
|
|
1896
|
+
private readonly _data;
|
|
1897
|
+
/** Set the embed title (shown in bold at the top). */
|
|
1898
|
+
setTitle(title: string): this;
|
|
1899
|
+
/** Set the main description text (supports markdown). */
|
|
1900
|
+
setDescription(description: string): this;
|
|
1901
|
+
/**
|
|
1902
|
+
* Set the accent colour.
|
|
1903
|
+
* @param color Hex string — e.g. `'#5865F2'` or `'5865F2'`
|
|
1904
|
+
*/
|
|
1905
|
+
setColor(color: string): this;
|
|
1906
|
+
/** Make the title a clickable hyperlink. */
|
|
1907
|
+
setUrl(url: string): this;
|
|
1908
|
+
/** Small image shown in the top-right corner. */
|
|
1909
|
+
setThumbnail(url: string): this;
|
|
1910
|
+
/** Large image shown below the fields. */
|
|
1911
|
+
setImage(url: string): this;
|
|
1912
|
+
/** Footer text shown at the very bottom of the embed. */
|
|
1913
|
+
setFooter(text: string): this;
|
|
1914
|
+
/**
|
|
1915
|
+
* Add a timestamp to the footer line.
|
|
1916
|
+
* @param date Defaults to `new Date()`.
|
|
1917
|
+
*/
|
|
1918
|
+
setTimestamp(date?: Date | number): this;
|
|
1919
|
+
/** Author name + optional icon shown above the title. */
|
|
1920
|
+
setAuthor(author: {
|
|
1921
|
+
name: string;
|
|
1922
|
+
iconUrl?: string;
|
|
1923
|
+
}): this;
|
|
1924
|
+
/**
|
|
1925
|
+
* Add a single field.
|
|
1926
|
+
* @param inline Pass `true` to render this field side-by-side with adjacent inline fields.
|
|
1927
|
+
*/
|
|
1928
|
+
addField(name: string, value: string, inline?: boolean): this;
|
|
1929
|
+
/** Add multiple fields at once. */
|
|
1930
|
+
addFields(...fields: EmbedField[]): this;
|
|
1931
|
+
/** Replace all fields. */
|
|
1932
|
+
setFields(fields: EmbedField[]): this;
|
|
1933
|
+
/** Serialise to a plain `Embed` object you can pass to any API call. */
|
|
1934
|
+
toJSON(): Embed;
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
type ButtonStyle = 'primary' | 'secondary' | 'success' | 'danger' | 'link';
|
|
1938
|
+
/**
|
|
1939
|
+
* Fluent builder for button components.
|
|
1940
|
+
*
|
|
1941
|
+
* @example
|
|
1942
|
+
* const row = new ActionRowBuilder()
|
|
1943
|
+
* .addButton(
|
|
1944
|
+
* new ButtonBuilder()
|
|
1945
|
+
* .setCustomId('confirm')
|
|
1946
|
+
* .setLabel('Confirm')
|
|
1947
|
+
* .setStyle('success')
|
|
1948
|
+
* )
|
|
1949
|
+
* .addButton(
|
|
1950
|
+
* new ButtonBuilder()
|
|
1951
|
+
* .setCustomId('cancel')
|
|
1952
|
+
* .setLabel('Cancel')
|
|
1953
|
+
* .setStyle('danger')
|
|
1954
|
+
* )
|
|
1955
|
+
*
|
|
1956
|
+
* await client.messages.send(channelId, { content: 'Are you sure?', components: row.toJSON() })
|
|
1957
|
+
*/
|
|
1958
|
+
declare class ButtonBuilder {
|
|
1959
|
+
private _customId;
|
|
1960
|
+
private _label;
|
|
1961
|
+
private _style;
|
|
1962
|
+
private _disabled;
|
|
1963
|
+
private _emoji?;
|
|
1964
|
+
private _url?;
|
|
1965
|
+
/** Custom ID returned in the `BUTTON_CLICK` interaction. Not required for `link` style buttons. */
|
|
1966
|
+
setCustomId(customId: string): this;
|
|
1967
|
+
/** Text displayed on the button. */
|
|
1968
|
+
setLabel(label: string): this;
|
|
1969
|
+
/**
|
|
1970
|
+
* Visual style:
|
|
1971
|
+
* - `primary` — blurple / brand colour
|
|
1972
|
+
* - `secondary` — grey
|
|
1973
|
+
* - `success` — green
|
|
1974
|
+
* - `danger` — red
|
|
1975
|
+
* - `link` — grey, navigates to a URL instead of creating an interaction
|
|
1976
|
+
*/
|
|
1977
|
+
setStyle(style: ButtonStyle): this;
|
|
1978
|
+
/** Emoji shown to the left of the label (unicode or custom e.g. `'👋'`). */
|
|
1979
|
+
setEmoji(emoji: string): this;
|
|
1980
|
+
/**
|
|
1981
|
+
* URL for `link` style buttons.
|
|
1982
|
+
* Sets the style to `'link'` automatically.
|
|
1983
|
+
*/
|
|
1984
|
+
setUrl(url: string): this;
|
|
1985
|
+
/** Prevent users from clicking the button. */
|
|
1986
|
+
setDisabled(disabled?: boolean): this;
|
|
1987
|
+
toJSON(): MessageComponent;
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1990
|
+
interface SelectMenuOption {
|
|
1991
|
+
/** Visible label shown to the user. */
|
|
1992
|
+
label: string;
|
|
1993
|
+
/** Value returned in the interaction's `values` array. */
|
|
1994
|
+
value: string;
|
|
1995
|
+
/** Optional description shown below the label. */
|
|
1996
|
+
description?: string;
|
|
1997
|
+
}
|
|
1998
|
+
/**
|
|
1999
|
+
* Fluent builder for select-menu (dropdown) components.
|
|
2000
|
+
*
|
|
2001
|
+
* @example
|
|
2002
|
+
* const menu = new SelectMenuBuilder()
|
|
2003
|
+
* .setCustomId('colour_pick')
|
|
2004
|
+
* .setPlaceholder('Pick a colour…')
|
|
2005
|
+
* .addOption({ label: 'Red', value: 'red' })
|
|
2006
|
+
* .addOption({ label: 'Green', value: 'green' })
|
|
2007
|
+
* .addOption({ label: 'Blue', value: 'blue' })
|
|
2008
|
+
*
|
|
2009
|
+
* await client.messages.send(channelId, { content: 'Choose:', components: [menu.toJSON()] })
|
|
2010
|
+
*/
|
|
2011
|
+
declare class SelectMenuBuilder {
|
|
2012
|
+
private _customId;
|
|
2013
|
+
private _placeholder?;
|
|
1159
2014
|
private _disabled;
|
|
1160
2015
|
private readonly _options;
|
|
1161
2016
|
/** Custom ID returned in the `SELECT_MENU` interaction. */
|
|
@@ -1173,92 +2028,829 @@ declare class SelectMenuBuilder {
|
|
|
1173
2028
|
toJSON(): MessageComponent;
|
|
1174
2029
|
}
|
|
1175
2030
|
|
|
1176
|
-
type ComponentBuilder = ButtonBuilder | SelectMenuBuilder | {
|
|
1177
|
-
toJSON(): MessageComponent;
|
|
1178
|
-
};
|
|
2031
|
+
type ComponentBuilder = ButtonBuilder | SelectMenuBuilder | {
|
|
2032
|
+
toJSON(): MessageComponent;
|
|
2033
|
+
};
|
|
2034
|
+
/**
|
|
2035
|
+
* Groups buttons (and/or a select menu) into a single row of components.
|
|
2036
|
+
*
|
|
2037
|
+
* @example
|
|
2038
|
+
* const row = new ActionRowBuilder()
|
|
2039
|
+
* .addComponent(new ButtonBuilder().setCustomId('yes').setLabel('Yes').setStyle('success'))
|
|
2040
|
+
* .addComponent(new ButtonBuilder().setCustomId('no').setLabel('No').setStyle('danger'))
|
|
2041
|
+
*
|
|
2042
|
+
* await interaction.reply({ content: 'Confirm?', components: row.toJSON() })
|
|
2043
|
+
*/
|
|
2044
|
+
declare class ActionRowBuilder {
|
|
2045
|
+
private readonly _components;
|
|
2046
|
+
/** Add a single component (button or select menu). */
|
|
2047
|
+
addComponent(component: ComponentBuilder): this;
|
|
2048
|
+
/** Add multiple components at once. */
|
|
2049
|
+
addComponents(...components: ComponentBuilder[]): this;
|
|
2050
|
+
/**
|
|
2051
|
+
* Serialise to a flat `MessageComponent[]` array — the format accepted by all API calls.
|
|
2052
|
+
*/
|
|
2053
|
+
toJSON(): MessageComponent[];
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
/**
|
|
2057
|
+
* Fluent builder for a single slash command option (parameter).
|
|
2058
|
+
* Obtain one via the callback in `SlashCommandBuilder.addStringOption()` etc.
|
|
2059
|
+
*/
|
|
2060
|
+
declare class SlashCommandOptionBuilder {
|
|
2061
|
+
private _data;
|
|
2062
|
+
constructor(type: SlashCommandOption['type']);
|
|
2063
|
+
/** Internal option name (lowercase, no spaces). Shown after `/command ` in the client UI. */
|
|
2064
|
+
setName(name: string): this;
|
|
2065
|
+
/** Short human-readable description shown in the command picker. */
|
|
2066
|
+
setDescription(description: string): this;
|
|
2067
|
+
/** Whether users must supply this option before sending the command. */
|
|
2068
|
+
setRequired(required?: boolean): this;
|
|
2069
|
+
/**
|
|
2070
|
+
* Restrict the option to specific values.
|
|
2071
|
+
* The picker will show these as autocomplete suggestions.
|
|
2072
|
+
*/
|
|
2073
|
+
addChoice(name: string, value: string | number): this;
|
|
2074
|
+
/** Set all allowed choices at once. */
|
|
2075
|
+
setChoices(choices: Array<{
|
|
2076
|
+
name: string;
|
|
2077
|
+
value: string | number;
|
|
2078
|
+
}>): this;
|
|
2079
|
+
toJSON(): SlashCommandOption;
|
|
2080
|
+
}
|
|
2081
|
+
/**
|
|
2082
|
+
* Fluent builder for slash commands.
|
|
2083
|
+
*
|
|
2084
|
+
* @example
|
|
2085
|
+
* await client.commands.setSlash([
|
|
2086
|
+
* new SlashCommandBuilder()
|
|
2087
|
+
* .setName('ban')
|
|
2088
|
+
* .setDescription('Ban a member from this server')
|
|
2089
|
+
* .addUserOption((opt) =>
|
|
2090
|
+
* opt.setName('user').setDescription('Who to ban').setRequired(true)
|
|
2091
|
+
* )
|
|
2092
|
+
* .addStringOption((opt) =>
|
|
2093
|
+
* opt.setName('reason').setDescription('Reason for the ban')
|
|
2094
|
+
* )
|
|
2095
|
+
* .toJSON(),
|
|
2096
|
+
* ])
|
|
2097
|
+
*/
|
|
2098
|
+
declare class SlashCommandBuilder {
|
|
2099
|
+
private _data;
|
|
2100
|
+
/** Command name — lowercase, no spaces (e.g. `'ban'`, `'server-info'`). */
|
|
2101
|
+
setName(name: string): this;
|
|
2102
|
+
/** Short description shown in the command picker UI. */
|
|
2103
|
+
setDescription(description: string): this;
|
|
2104
|
+
/** Add a text (string) option. */
|
|
2105
|
+
addStringOption(fn: (opt: SlashCommandOptionBuilder) => SlashCommandOptionBuilder): this;
|
|
2106
|
+
/** Add an integer (whole number) option. */
|
|
2107
|
+
addIntegerOption(fn: (opt: SlashCommandOptionBuilder) => SlashCommandOptionBuilder): this;
|
|
2108
|
+
/** Add a boolean (true/false) option. */
|
|
2109
|
+
addBooleanOption(fn: (opt: SlashCommandOptionBuilder) => SlashCommandOptionBuilder): this;
|
|
2110
|
+
/** Add a user-mention option (returns a user ID string). */
|
|
2111
|
+
addUserOption(fn: (opt: SlashCommandOptionBuilder) => SlashCommandOptionBuilder): this;
|
|
2112
|
+
/** Add a channel-mention option (returns a channel ID string). */
|
|
2113
|
+
addChannelOption(fn: (opt: SlashCommandOptionBuilder) => SlashCommandOptionBuilder): this;
|
|
2114
|
+
/** Add a role-mention option (returns a role ID string). */
|
|
2115
|
+
addRoleOption(fn: (opt: SlashCommandOptionBuilder) => SlashCommandOptionBuilder): this;
|
|
2116
|
+
toJSON(): SlashCommandDefinition;
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
interface PollOption {
|
|
2120
|
+
label: string;
|
|
2121
|
+
emoji?: string;
|
|
2122
|
+
value?: string;
|
|
2123
|
+
}
|
|
2124
|
+
interface PollDefinition {
|
|
2125
|
+
question: string;
|
|
2126
|
+
options: PollOption[];
|
|
2127
|
+
allowMultiple?: boolean;
|
|
2128
|
+
duration?: number | null;
|
|
2129
|
+
anonymous?: boolean;
|
|
2130
|
+
}
|
|
2131
|
+
/**
|
|
2132
|
+
* Fluent builder for creating polls.
|
|
2133
|
+
*
|
|
2134
|
+
* @example
|
|
2135
|
+
* const poll = new PollBuilder()
|
|
2136
|
+
* .setQuestion('What is your favourite colour?')
|
|
2137
|
+
* .addOption({ label: 'Red', emoji: '🔴' })
|
|
2138
|
+
* .addOption({ label: 'Green', emoji: '🟢' })
|
|
2139
|
+
* .addOption({ label: 'Blue', emoji: '🔵' })
|
|
2140
|
+
* .setDuration(60 * 60 * 24) // 24 hours in seconds
|
|
2141
|
+
* .toJSON()
|
|
2142
|
+
*
|
|
2143
|
+
* await client.messages.send(channelId, { poll })
|
|
2144
|
+
*/
|
|
2145
|
+
declare class PollBuilder {
|
|
2146
|
+
private _question;
|
|
2147
|
+
private _options;
|
|
2148
|
+
private _allowMultiple;
|
|
2149
|
+
private _duration;
|
|
2150
|
+
private _anonymous;
|
|
2151
|
+
/**
|
|
2152
|
+
* Set the poll question.
|
|
2153
|
+
*
|
|
2154
|
+
* @example
|
|
2155
|
+
* builder.setQuestion('Best programming language?')
|
|
2156
|
+
*/
|
|
2157
|
+
setQuestion(question: string): this;
|
|
2158
|
+
/**
|
|
2159
|
+
* Add a single answer option.
|
|
2160
|
+
*
|
|
2161
|
+
* @example
|
|
2162
|
+
* builder.addOption({ label: 'TypeScript', emoji: '🔷' })
|
|
2163
|
+
*/
|
|
2164
|
+
addOption(option: PollOption): this;
|
|
2165
|
+
/**
|
|
2166
|
+
* Add multiple answer options at once.
|
|
2167
|
+
*
|
|
2168
|
+
* @example
|
|
2169
|
+
* builder.addOptions([
|
|
2170
|
+
* { label: 'Yes', emoji: '✅' },
|
|
2171
|
+
* { label: 'No', emoji: '❌' },
|
|
2172
|
+
* ])
|
|
2173
|
+
*/
|
|
2174
|
+
addOptions(options: PollOption[]): this;
|
|
2175
|
+
/**
|
|
2176
|
+
* Allow users to select more than one option.
|
|
2177
|
+
* Default: `false` (single choice).
|
|
2178
|
+
*/
|
|
2179
|
+
setAllowMultiple(yes?: boolean): this;
|
|
2180
|
+
/**
|
|
2181
|
+
* Set the poll duration in **seconds**. Pass `null` to make it permanent.
|
|
2182
|
+
*
|
|
2183
|
+
* @example
|
|
2184
|
+
* builder.setDuration(60 * 60 * 24) // expires in 24 hours
|
|
2185
|
+
* builder.setDuration(null) // no expiry
|
|
2186
|
+
*/
|
|
2187
|
+
setDuration(seconds: number | null): this;
|
|
2188
|
+
/**
|
|
2189
|
+
* Hide which users voted for which option.
|
|
2190
|
+
* Default: `false` (votes are public).
|
|
2191
|
+
*/
|
|
2192
|
+
setAnonymous(yes?: boolean): this;
|
|
2193
|
+
/** Build the poll definition object. */
|
|
2194
|
+
toJSON(): PollDefinition;
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
/**
|
|
2198
|
+
* Fluent builder for composing messages.
|
|
2199
|
+
* Replaces passing raw option objects everywhere.
|
|
2200
|
+
*
|
|
2201
|
+
* @example
|
|
2202
|
+
* const msg = new MessageBuilder()
|
|
2203
|
+
* .setContent('Here are your stats:')
|
|
2204
|
+
* .setEmbed(
|
|
2205
|
+
* new EmbedBuilder()
|
|
2206
|
+
* .setTitle('📊 Stats')
|
|
2207
|
+
* .addField('Messages', '1 234', true)
|
|
2208
|
+
* .addField('Reactions', '567', true)
|
|
2209
|
+
* .setColor('#5865F2')
|
|
2210
|
+
* )
|
|
2211
|
+
* .addRow(
|
|
2212
|
+
* new ActionRowBuilder()
|
|
2213
|
+
* .addComponent(new ButtonBuilder().setLabel('Refresh').setCustomId('refresh').setStyle('primary'))
|
|
2214
|
+
* )
|
|
2215
|
+
* .toJSON()
|
|
2216
|
+
*
|
|
2217
|
+
* await client.messages.send(channelId, msg)
|
|
2218
|
+
*/
|
|
2219
|
+
declare class MessageBuilder {
|
|
2220
|
+
private _content;
|
|
2221
|
+
private _embed;
|
|
2222
|
+
private _components;
|
|
2223
|
+
private _replyToId;
|
|
2224
|
+
private _poll;
|
|
2225
|
+
/**
|
|
2226
|
+
* Set the text content of the message.
|
|
2227
|
+
*
|
|
2228
|
+
* @example
|
|
2229
|
+
* builder.setContent('Hello world!')
|
|
2230
|
+
*/
|
|
2231
|
+
setContent(content: string): this;
|
|
2232
|
+
/**
|
|
2233
|
+
* Attach an embed. Accepts an `EmbedBuilder` or raw `Embed` object.
|
|
2234
|
+
*
|
|
2235
|
+
* @example
|
|
2236
|
+
* builder.setEmbed(new EmbedBuilder().setTitle('Result'))
|
|
2237
|
+
* builder.setEmbed({ title: 'Result', color: '#57F287' })
|
|
2238
|
+
*/
|
|
2239
|
+
setEmbed(embed: EmbedBuilder | Embed): this;
|
|
2240
|
+
/**
|
|
2241
|
+
* Remove any embed from this message.
|
|
2242
|
+
*/
|
|
2243
|
+
clearEmbed(): this;
|
|
2244
|
+
/**
|
|
2245
|
+
* Add an `ActionRowBuilder` (or raw component array) as a component row.
|
|
2246
|
+
*
|
|
2247
|
+
* @example
|
|
2248
|
+
* builder.addRow(
|
|
2249
|
+
* new ActionRowBuilder().addComponent(btn1).addComponent(btn2)
|
|
2250
|
+
* )
|
|
2251
|
+
*/
|
|
2252
|
+
addRow(row: ActionRowBuilder | MessageComponent[]): this;
|
|
2253
|
+
/**
|
|
2254
|
+
* Replace all existing component rows.
|
|
2255
|
+
*/
|
|
2256
|
+
setComponents(components: MessageComponent[]): this;
|
|
2257
|
+
/**
|
|
2258
|
+
* Set the message this is replying to.
|
|
2259
|
+
*
|
|
2260
|
+
* @example
|
|
2261
|
+
* builder.setReplyTo(message.id)
|
|
2262
|
+
*/
|
|
2263
|
+
setReplyTo(messageId: string): this;
|
|
2264
|
+
/**
|
|
2265
|
+
* Attach a poll to the message.
|
|
2266
|
+
* Accepts a `PollBuilder` or raw `PollDefinition`.
|
|
2267
|
+
*
|
|
2268
|
+
* @example
|
|
2269
|
+
* builder.setPoll(
|
|
2270
|
+
* new PollBuilder()
|
|
2271
|
+
* .setQuestion('Favourite language?')
|
|
2272
|
+
* .addOptions([{ label: 'TypeScript' }, { label: 'Python' }])
|
|
2273
|
+
* )
|
|
2274
|
+
*/
|
|
2275
|
+
setPoll(poll: {
|
|
2276
|
+
toJSON: () => PollDefinition;
|
|
2277
|
+
} | PollDefinition): this;
|
|
2278
|
+
/**
|
|
2279
|
+
* Build the message options object, ready to pass to `client.messages.send()`.
|
|
2280
|
+
*
|
|
2281
|
+
* @throws if neither `content` nor `embed` nor `poll` is set.
|
|
2282
|
+
*/
|
|
2283
|
+
toJSON(): SendMessageOptions & {
|
|
2284
|
+
poll?: PollDefinition;
|
|
2285
|
+
};
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
/**
|
|
2289
|
+
* A supercharged Map with extra utility methods.
|
|
2290
|
+
* Used throughout the SDK for caches (messages, channels, members, etc.)
|
|
2291
|
+
*
|
|
2292
|
+
* Inspired by discord.js Collection — but with proper generics and async support.
|
|
2293
|
+
*
|
|
2294
|
+
* @example
|
|
2295
|
+
* const col = new Collection<string, User>()
|
|
2296
|
+
* col.set('u1', { id: 'u1', name: 'Alice' })
|
|
2297
|
+
* col.set('u2', { id: 'u2', name: 'Bob' })
|
|
2298
|
+
*
|
|
2299
|
+
* col.first() // { id: 'u1', name: 'Alice' }
|
|
2300
|
+
* col.find(u => u.name === 'Bob') // { id: 'u2', name: 'Bob' }
|
|
2301
|
+
* col.map(u => u.name) // ['Alice', 'Bob']
|
|
2302
|
+
*/
|
|
2303
|
+
declare class Collection<K, V> extends Map<K, V> {
|
|
2304
|
+
/**
|
|
2305
|
+
* The first value stored (insertion order), or `undefined` if empty.
|
|
2306
|
+
*/
|
|
2307
|
+
first(): V | undefined;
|
|
2308
|
+
/**
|
|
2309
|
+
* The first `n` values stored (insertion order).
|
|
2310
|
+
*/
|
|
2311
|
+
firstN(n: number): V[];
|
|
2312
|
+
/**
|
|
2313
|
+
* The last value stored, or `undefined` if empty.
|
|
2314
|
+
*/
|
|
2315
|
+
last(): V | undefined;
|
|
2316
|
+
/**
|
|
2317
|
+
* The last `n` values stored (insertion order).
|
|
2318
|
+
*/
|
|
2319
|
+
lastN(n: number): V[];
|
|
2320
|
+
/**
|
|
2321
|
+
* Returns a random value from the collection, or `undefined` if empty.
|
|
2322
|
+
*/
|
|
2323
|
+
random(): V | undefined;
|
|
2324
|
+
/**
|
|
2325
|
+
* Find the first value that passes the predicate.
|
|
2326
|
+
*
|
|
2327
|
+
* @example
|
|
2328
|
+
* const bot = members.find(m => m.user.isBot)
|
|
2329
|
+
*/
|
|
2330
|
+
find(fn: (value: V, key: K, col: this) => boolean): V | undefined;
|
|
2331
|
+
/**
|
|
2332
|
+
* Find the key of the first value that passes the predicate.
|
|
2333
|
+
*/
|
|
2334
|
+
findKey(fn: (value: V, key: K, col: this) => boolean): K | undefined;
|
|
2335
|
+
/**
|
|
2336
|
+
* Returns `true` if at least one value satisfies the predicate.
|
|
2337
|
+
*/
|
|
2338
|
+
some(fn: (value: V, key: K, col: this) => boolean): boolean;
|
|
2339
|
+
/**
|
|
2340
|
+
* Returns `true` if every value satisfies the predicate.
|
|
2341
|
+
*/
|
|
2342
|
+
every(fn: (value: V, key: K, col: this) => boolean): boolean;
|
|
2343
|
+
/**
|
|
2344
|
+
* Filter to a new Collection containing only values that pass the predicate.
|
|
2345
|
+
*
|
|
2346
|
+
* @example
|
|
2347
|
+
* const admins = members.filter(m => m.role === 'ADMIN')
|
|
2348
|
+
*/
|
|
2349
|
+
filter(fn: (value: V, key: K, col: this) => boolean): Collection<K, V>;
|
|
2350
|
+
/**
|
|
2351
|
+
* Map each value to a new array.
|
|
2352
|
+
*
|
|
2353
|
+
* @example
|
|
2354
|
+
* const names = members.map(m => m.user.username)
|
|
2355
|
+
*/
|
|
2356
|
+
map<T>(fn: (value: V, key: K, col: this) => T): T[];
|
|
2357
|
+
/**
|
|
2358
|
+
* Map to a new Collection with transformed values.
|
|
2359
|
+
*
|
|
2360
|
+
* @example
|
|
2361
|
+
* const names = channels.mapValues(c => c.name.toUpperCase())
|
|
2362
|
+
*/
|
|
2363
|
+
mapValues<T>(fn: (value: V, key: K, col: this) => T): Collection<K, T>;
|
|
2364
|
+
/**
|
|
2365
|
+
* Reduce the collection to a single value.
|
|
2366
|
+
*
|
|
2367
|
+
* @example
|
|
2368
|
+
* const totalReactions = messages.reduce((sum, m) => sum + m.reactions.length, 0)
|
|
2369
|
+
*/
|
|
2370
|
+
reduce<T>(fn: (accumulator: T, value: V, key: K, col: this) => T, initial: T): T;
|
|
2371
|
+
/**
|
|
2372
|
+
* Returns values as an array (insertion order).
|
|
2373
|
+
*/
|
|
2374
|
+
toArray(): V[];
|
|
2375
|
+
/**
|
|
2376
|
+
* Returns keys as an array (insertion order).
|
|
2377
|
+
*/
|
|
2378
|
+
keyArray(): K[];
|
|
2379
|
+
/**
|
|
2380
|
+
* Sort and return a new Collection.
|
|
2381
|
+
* Callback works like `Array.prototype.sort`.
|
|
2382
|
+
*
|
|
2383
|
+
* @example
|
|
2384
|
+
* const sorted = channels.sort((a, b) => a.position - b.position)
|
|
2385
|
+
*/
|
|
2386
|
+
sort(fn?: (a: V, b: V, ak: K, bk: K) => number): Collection<K, V>;
|
|
2387
|
+
/**
|
|
2388
|
+
* Split into two Collections based on a predicate.
|
|
2389
|
+
* Returns `[passing, failing]`.
|
|
2390
|
+
*
|
|
2391
|
+
* @example
|
|
2392
|
+
* const [bots, humans] = members.partition(m => m.user.isBot)
|
|
2393
|
+
*/
|
|
2394
|
+
partition(fn: (value: V, key: K, col: this) => boolean): [Collection<K, V>, Collection<K, V>];
|
|
2395
|
+
/**
|
|
2396
|
+
* Merge this collection with one or more others.
|
|
2397
|
+
* Later collections overwrite duplicate keys.
|
|
2398
|
+
*/
|
|
2399
|
+
merge(...others: ReadonlyMap<K, V>[]): Collection<K, V>;
|
|
2400
|
+
/**
|
|
2401
|
+
* Serialize to a plain `Record` (requires string keys).
|
|
2402
|
+
*/
|
|
2403
|
+
toJSON(): Record<string, V>;
|
|
2404
|
+
toString(): string;
|
|
2405
|
+
}
|
|
2406
|
+
|
|
1179
2407
|
/**
|
|
1180
|
-
*
|
|
2408
|
+
* Per-user cooldown manager.
|
|
2409
|
+
* Prevents commands from being spammed by individual users.
|
|
1181
2410
|
*
|
|
1182
2411
|
* @example
|
|
1183
|
-
*
|
|
1184
|
-
*
|
|
1185
|
-
* .addComponent(new ButtonBuilder().setCustomId('no').setLabel('No').setStyle('danger'))
|
|
2412
|
+
* // Create once per command
|
|
2413
|
+
* const cooldown = new Cooldown(5_000) // 5 second cooldown
|
|
1186
2414
|
*
|
|
1187
|
-
*
|
|
2415
|
+
* client.command('daily', async (interaction) => {
|
|
2416
|
+
* const remaining = cooldown.check(interaction.userId)
|
|
2417
|
+
* if (remaining > 0) {
|
|
2418
|
+
* return interaction.replyEphemeral(
|
|
2419
|
+
* `⏳ Wait **${Cooldown.format(remaining)}** before using this command again.`
|
|
2420
|
+
* )
|
|
2421
|
+
* }
|
|
2422
|
+
* cooldown.use(interaction.userId)
|
|
2423
|
+
* await interaction.reply('🎁 Daily reward collected!')
|
|
2424
|
+
* })
|
|
1188
2425
|
*/
|
|
1189
|
-
declare class
|
|
1190
|
-
private readonly
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
/** Add multiple components at once. */
|
|
1194
|
-
addComponents(...components: ComponentBuilder[]): this;
|
|
2426
|
+
declare class Cooldown {
|
|
2427
|
+
private readonly _durations;
|
|
2428
|
+
private readonly _last;
|
|
2429
|
+
private readonly _defaultMs;
|
|
1195
2430
|
/**
|
|
1196
|
-
*
|
|
2431
|
+
* @param durationMs - Default cooldown duration in milliseconds.
|
|
1197
2432
|
*/
|
|
1198
|
-
|
|
2433
|
+
constructor(durationMs: number);
|
|
2434
|
+
/**
|
|
2435
|
+
* Check remaining cooldown for a user.
|
|
2436
|
+
* Returns `0` if they are not on cooldown (free to proceed),
|
|
2437
|
+
* or the **milliseconds remaining** if they are on cooldown.
|
|
2438
|
+
*
|
|
2439
|
+
* @example
|
|
2440
|
+
* const ms = cooldown.check(userId)
|
|
2441
|
+
* if (ms > 0) return interaction.replyEphemeral(`Wait ${Cooldown.format(ms)}!`)
|
|
2442
|
+
*/
|
|
2443
|
+
check(userId: string): number;
|
|
2444
|
+
/**
|
|
2445
|
+
* Mark a user as having just used the command, starting their cooldown.
|
|
2446
|
+
* Optionally override the cooldown duration for this specific user.
|
|
2447
|
+
*
|
|
2448
|
+
* @example
|
|
2449
|
+
* cooldown.use(userId) // uses default duration
|
|
2450
|
+
* cooldown.use(userId, 10_000) // 10 second cooldown for this use
|
|
2451
|
+
*/
|
|
2452
|
+
use(userId: string, durationMs?: number): void;
|
|
2453
|
+
/**
|
|
2454
|
+
* Immediately reset (clear) the cooldown for a user.
|
|
2455
|
+
*
|
|
2456
|
+
* @example
|
|
2457
|
+
* cooldown.reset(userId) // user can use the command again immediately
|
|
2458
|
+
*/
|
|
2459
|
+
reset(userId: string): void;
|
|
2460
|
+
/**
|
|
2461
|
+
* Reset all active cooldowns.
|
|
2462
|
+
*/
|
|
2463
|
+
resetAll(): void;
|
|
2464
|
+
/**
|
|
2465
|
+
* Returns a list of all users currently on cooldown.
|
|
2466
|
+
*
|
|
2467
|
+
* @example
|
|
2468
|
+
* const active = cooldown.activeCooldowns()
|
|
2469
|
+
* // [{ userId: 'abc', remainingMs: 3200 }, ...]
|
|
2470
|
+
*/
|
|
2471
|
+
activeCooldowns(): Array<{
|
|
2472
|
+
userId: string;
|
|
2473
|
+
remainingMs: number;
|
|
2474
|
+
}>;
|
|
2475
|
+
/**
|
|
2476
|
+
* Format milliseconds into a human-readable string.
|
|
2477
|
+
*
|
|
2478
|
+
* @example
|
|
2479
|
+
* Cooldown.format(3_600_000) // '1h 0m 0s'
|
|
2480
|
+
* Cooldown.format(90_000) // '1m 30s'
|
|
2481
|
+
* Cooldown.format(4_000) // '4s'
|
|
2482
|
+
*/
|
|
2483
|
+
static format(ms: number): string;
|
|
2484
|
+
}
|
|
2485
|
+
/**
|
|
2486
|
+
* Manages multiple named cooldowns in one place.
|
|
2487
|
+
* Ideal when you have many commands each with their own cooldown.
|
|
2488
|
+
*
|
|
2489
|
+
* @example
|
|
2490
|
+
* const cooldowns = new CooldownManager()
|
|
2491
|
+
*
|
|
2492
|
+
* client.command('ping', async (interaction) => {
|
|
2493
|
+
* const remaining = cooldowns.check('ping', interaction.userId, 3_000)
|
|
2494
|
+
* if (remaining > 0) return interaction.replyEphemeral(`Wait ${Cooldown.format(remaining)}!`)
|
|
2495
|
+
* await interaction.reply('Pong!')
|
|
2496
|
+
* })
|
|
2497
|
+
*/
|
|
2498
|
+
declare class CooldownManager {
|
|
2499
|
+
private readonly _map;
|
|
2500
|
+
/**
|
|
2501
|
+
* Get or create a named cooldown.
|
|
2502
|
+
*/
|
|
2503
|
+
get(name: string, durationMs?: number): Cooldown;
|
|
2504
|
+
/**
|
|
2505
|
+
* Check a named cooldown for a user.
|
|
2506
|
+
* Creates the cooldown if it doesn't exist yet.
|
|
2507
|
+
* Returns `0` if free, or remaining ms if on cooldown.
|
|
2508
|
+
*
|
|
2509
|
+
* @example
|
|
2510
|
+
* const ms = cooldowns.check('ban', userId, 30_000)
|
|
2511
|
+
*/
|
|
2512
|
+
check(name: string, userId: string, durationMs?: number): number;
|
|
2513
|
+
/**
|
|
2514
|
+
* Mark a user as having used a named command.
|
|
2515
|
+
*
|
|
2516
|
+
* @example
|
|
2517
|
+
* cooldowns.use('ban', userId, 30_000)
|
|
2518
|
+
*/
|
|
2519
|
+
use(name: string, userId: string, durationMs?: number): void;
|
|
2520
|
+
/**
|
|
2521
|
+
* Reset a user's cooldown on a named command.
|
|
2522
|
+
*/
|
|
2523
|
+
reset(name: string, userId: string): void;
|
|
2524
|
+
/**
|
|
2525
|
+
* Reset all cooldowns for all commands.
|
|
2526
|
+
*/
|
|
2527
|
+
resetAll(): void;
|
|
1199
2528
|
}
|
|
1200
2529
|
|
|
1201
2530
|
/**
|
|
1202
|
-
*
|
|
1203
|
-
*
|
|
2531
|
+
* Coloured, timestamped logger for Nova bots.
|
|
2532
|
+
* Prefix every log with a consistent `[BotName]` tag.
|
|
2533
|
+
*
|
|
2534
|
+
* @example
|
|
2535
|
+
* const log = new Logger('MyBot')
|
|
2536
|
+
* log.info('Ready!') // [MyBot] [INFO] Ready!
|
|
2537
|
+
* log.warn('Rate limited') // [MyBot] [WARN] Rate limited
|
|
2538
|
+
* log.error('DB timed out') // [MyBot] [ERROR] DB timed out
|
|
2539
|
+
* log.debug('Payload:', data) // [MyBot] [DEBUG] Payload: { ... }
|
|
2540
|
+
* log.success('Command registered') // [MyBot] [OK] Command registered
|
|
2541
|
+
* log.command('ping', userId) // [MyBot] [CMD] ping ← userId
|
|
2542
|
+
* log.event('messageCreate') // [MyBot] [EVT] messageCreate
|
|
1204
2543
|
*/
|
|
1205
|
-
declare class
|
|
1206
|
-
private
|
|
1207
|
-
|
|
1208
|
-
/** Internal option name (lowercase, no spaces). Shown after `/command ` in the client UI. */
|
|
1209
|
-
setName(name: string): this;
|
|
1210
|
-
/** Short human-readable description shown in the command picker. */
|
|
1211
|
-
setDescription(description: string): this;
|
|
1212
|
-
/** Whether users must supply this option before sending the command. */
|
|
1213
|
-
setRequired(required?: boolean): this;
|
|
2544
|
+
declare class Logger {
|
|
2545
|
+
private readonly _prefix;
|
|
2546
|
+
private _debug;
|
|
1214
2547
|
/**
|
|
1215
|
-
*
|
|
1216
|
-
*
|
|
2548
|
+
* @param name - Name shown in square brackets before every message.
|
|
2549
|
+
* @param enableDebug - When `false` (default), `.debug()` calls are silent.
|
|
1217
2550
|
*/
|
|
1218
|
-
|
|
1219
|
-
/**
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
2551
|
+
constructor(name: string, enableDebug?: boolean);
|
|
2552
|
+
/** Enable or disable debug output at runtime. */
|
|
2553
|
+
setDebug(enabled: boolean): this;
|
|
2554
|
+
private _timestamp;
|
|
2555
|
+
private _fmt;
|
|
2556
|
+
/** General info message. */
|
|
2557
|
+
info(...args: unknown[]): void;
|
|
2558
|
+
/** Warning — something unexpected but non-fatal. */
|
|
2559
|
+
warn(...args: unknown[]): void;
|
|
2560
|
+
/** Error — something went wrong. */
|
|
2561
|
+
error(...args: unknown[]): void;
|
|
2562
|
+
/** Success / positive confirmation. */
|
|
2563
|
+
success(...args: unknown[]): void;
|
|
2564
|
+
/** Debug — only printed when `enableDebug` is true. */
|
|
2565
|
+
debug(...args: unknown[]): void;
|
|
2566
|
+
/**
|
|
2567
|
+
* Log an incoming command interaction.
|
|
2568
|
+
*
|
|
2569
|
+
* @example
|
|
2570
|
+
* log.command('ping', interaction.userId)
|
|
2571
|
+
* // [MyBot] [CMD] /ping ← user:abc123
|
|
2572
|
+
*/
|
|
2573
|
+
command(name: string, userId: string): void;
|
|
2574
|
+
/**
|
|
2575
|
+
* Log a gateway event.
|
|
2576
|
+
*
|
|
2577
|
+
* @example
|
|
2578
|
+
* log.event('messageCreate')
|
|
2579
|
+
*/
|
|
2580
|
+
event(type: string, extra?: string): void;
|
|
2581
|
+
/**
|
|
2582
|
+
* Log that a command handler threw an error.
|
|
2583
|
+
*
|
|
2584
|
+
* @example
|
|
2585
|
+
* log.commandError('ban', err)
|
|
2586
|
+
*/
|
|
2587
|
+
commandError(name: string, err: unknown): void;
|
|
1225
2588
|
}
|
|
2589
|
+
|
|
1226
2590
|
/**
|
|
1227
|
-
*
|
|
2591
|
+
* Async cursor-based paginator for any list API.
|
|
2592
|
+
*
|
|
2593
|
+
* Pass a `fetchFn` that takes the current cursor and returns the next
|
|
2594
|
+
* page of items plus the cursor to use for the next page (`null` = done).
|
|
1228
2595
|
*
|
|
1229
2596
|
* @example
|
|
1230
|
-
*
|
|
1231
|
-
*
|
|
1232
|
-
*
|
|
1233
|
-
*
|
|
1234
|
-
*
|
|
1235
|
-
*
|
|
1236
|
-
*
|
|
1237
|
-
*
|
|
1238
|
-
*
|
|
1239
|
-
*
|
|
1240
|
-
*
|
|
1241
|
-
*
|
|
2597
|
+
* // Paginate all messages in a channel
|
|
2598
|
+
* const paginator = new Paginator(async (cursor) => {
|
|
2599
|
+
* const messages = await client.messages.fetch(channelId, { limit: 50, before: cursor ?? undefined })
|
|
2600
|
+
* return { items: messages, cursor: messages.at(-1)?.id ?? null }
|
|
2601
|
+
* })
|
|
2602
|
+
*
|
|
2603
|
+
* // Lazy async iteration
|
|
2604
|
+
* for await (const message of paginator) {
|
|
2605
|
+
* console.log(message.content)
|
|
2606
|
+
* }
|
|
2607
|
+
*
|
|
2608
|
+
* // Or collect everything at once
|
|
2609
|
+
* const all = await paginator.fetchAll()
|
|
1242
2610
|
*/
|
|
1243
|
-
declare class
|
|
1244
|
-
private
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
2611
|
+
declare class Paginator<T> {
|
|
2612
|
+
private readonly fetchFn;
|
|
2613
|
+
private _cursor;
|
|
2614
|
+
private _done;
|
|
2615
|
+
private _totalFetched;
|
|
2616
|
+
constructor(fetchFn: (cursor: string | null) => Promise<{
|
|
2617
|
+
items: T[];
|
|
2618
|
+
cursor: string | null;
|
|
2619
|
+
}>);
|
|
2620
|
+
/** Whether all pages have been consumed. */
|
|
2621
|
+
get done(): boolean;
|
|
2622
|
+
/** Total number of items fetched so far (across all pages). */
|
|
2623
|
+
get totalFetched(): number;
|
|
2624
|
+
/**
|
|
2625
|
+
* Fetch the next page of results.
|
|
2626
|
+
* Returns an empty array when there are no more pages.
|
|
2627
|
+
*
|
|
2628
|
+
* @example
|
|
2629
|
+
* const page1 = await paginator.fetchPage()
|
|
2630
|
+
* const page2 = await paginator.fetchPage()
|
|
2631
|
+
*/
|
|
2632
|
+
fetchPage(): Promise<T[]>;
|
|
2633
|
+
/**
|
|
2634
|
+
* Fetch **all** remaining pages and return a flat array.
|
|
2635
|
+
*
|
|
2636
|
+
* ⚠️ Use with caution on very large collections.
|
|
2637
|
+
*
|
|
2638
|
+
* @example
|
|
2639
|
+
* const allMembers = await paginator.fetchAll()
|
|
2640
|
+
*/
|
|
2641
|
+
fetchAll(): Promise<T[]>;
|
|
2642
|
+
/**
|
|
2643
|
+
* Fetch up to `n` items total (across however many pages are needed).
|
|
2644
|
+
*
|
|
2645
|
+
* @example
|
|
2646
|
+
* const first100 = await paginator.fetchN(100)
|
|
2647
|
+
*/
|
|
2648
|
+
fetchN(n: number): Promise<T[]>;
|
|
2649
|
+
/**
|
|
2650
|
+
* Async-iterate over every item, one page at a time.
|
|
2651
|
+
*
|
|
2652
|
+
* @example
|
|
2653
|
+
* for await (const msg of paginator) {
|
|
2654
|
+
* process(msg)
|
|
2655
|
+
* }
|
|
2656
|
+
*/
|
|
2657
|
+
[Symbol.asyncIterator](): AsyncGenerator<T>;
|
|
2658
|
+
/**
|
|
2659
|
+
* Reset the paginator so you can iterate from the beginning again.
|
|
2660
|
+
*
|
|
2661
|
+
* @example
|
|
2662
|
+
* await paginator.fetchAll()
|
|
2663
|
+
* paginator.reset()
|
|
2664
|
+
* const againFirst = await paginator.fetchPage()
|
|
2665
|
+
*/
|
|
2666
|
+
reset(): void;
|
|
2667
|
+
}
|
|
2668
|
+
|
|
2669
|
+
/**
|
|
2670
|
+
* All known Nova bot permission keys.
|
|
2671
|
+
* Use these as string constants when calling `has()`, `grant()`, etc.
|
|
2672
|
+
*/
|
|
2673
|
+
declare const Permissions: {
|
|
2674
|
+
/** Read messages in channels. */
|
|
2675
|
+
readonly MESSAGES_READ: "messages.read";
|
|
2676
|
+
/** Send messages in channels. */
|
|
2677
|
+
readonly MESSAGES_WRITE: "messages.write";
|
|
2678
|
+
/** Edit / delete any message (not just the bot's own). */
|
|
2679
|
+
readonly MESSAGES_MANAGE: "messages.manage";
|
|
2680
|
+
/** Create, edit and delete channels. */
|
|
2681
|
+
readonly CHANNELS_MANAGE: "channels.manage";
|
|
2682
|
+
/** Kick members from the server. */
|
|
2683
|
+
readonly MEMBERS_KICK: "members.kick";
|
|
2684
|
+
/** Ban and unban members from the server. */
|
|
2685
|
+
readonly MEMBERS_BAN: "members.ban";
|
|
2686
|
+
/** Assign and remove roles on members. */
|
|
2687
|
+
readonly MEMBERS_ROLES: "members.roles";
|
|
2688
|
+
/** Edit server settings. */
|
|
2689
|
+
readonly SERVERS_MANAGE: "servers.manage";
|
|
2690
|
+
};
|
|
2691
|
+
type PermissionKey = (typeof Permissions)[keyof typeof Permissions];
|
|
2692
|
+
/**
|
|
2693
|
+
* Utility class for working with Nova bot permission records.
|
|
2694
|
+
*
|
|
2695
|
+
* Unlike a Discord-style bitfield, Nova permissions are stored as a
|
|
2696
|
+
* `Record<string, boolean>` map. `PermissionsBitfield` wraps that
|
|
2697
|
+
* map with readable helpers for checking, merging, and diffing.
|
|
2698
|
+
*
|
|
2699
|
+
* @example
|
|
2700
|
+
* const perms = new PermissionsBitfield({
|
|
2701
|
+
* 'messages.read': true,
|
|
2702
|
+
* 'messages.write': true,
|
|
2703
|
+
* })
|
|
2704
|
+
*
|
|
2705
|
+
* perms.has('messages.read') // true
|
|
2706
|
+
* perms.has('channels.manage') // false
|
|
2707
|
+
* perms.hasAll('messages.read', 'messages.write') // true
|
|
2708
|
+
* perms.missing('messages.manage', 'members.kick') // ['messages.manage', 'members.kick']
|
|
2709
|
+
* perms.toArray() // ['messages.read', 'messages.write']
|
|
2710
|
+
*/
|
|
2711
|
+
declare class PermissionsBitfield {
|
|
2712
|
+
private readonly _perms;
|
|
2713
|
+
constructor(perms?: Record<string, boolean>);
|
|
2714
|
+
/**
|
|
2715
|
+
* Returns `true` if the given permission is explicitly granted.
|
|
2716
|
+
*
|
|
2717
|
+
* @example
|
|
2718
|
+
* if (!perms.has(Permissions.MESSAGES_WRITE)) {
|
|
2719
|
+
* throw new Error('Bot cannot write messages here.')
|
|
2720
|
+
* }
|
|
2721
|
+
*/
|
|
2722
|
+
has(permission: string): boolean;
|
|
2723
|
+
/**
|
|
2724
|
+
* Returns `true` if **all** listed permissions are granted.
|
|
2725
|
+
*
|
|
2726
|
+
* @example
|
|
2727
|
+
* perms.hasAll('messages.read', 'messages.write') // true
|
|
2728
|
+
*/
|
|
2729
|
+
hasAll(...permissions: string[]): boolean;
|
|
2730
|
+
/**
|
|
2731
|
+
* Returns `true` if **at least one** of the listed permissions is granted.
|
|
2732
|
+
*
|
|
2733
|
+
* @example
|
|
2734
|
+
* perms.hasAny('channels.manage', 'servers.manage') // true if either is set
|
|
2735
|
+
*/
|
|
2736
|
+
hasAny(...permissions: string[]): boolean;
|
|
2737
|
+
/**
|
|
2738
|
+
* Returns the list of permissions that are **not** granted.
|
|
2739
|
+
*
|
|
2740
|
+
* @example
|
|
2741
|
+
* const missing = perms.missing('messages.write', 'members.kick')
|
|
2742
|
+
* if (missing.length) throw new Error(`Missing: ${missing.join(', ')}`)
|
|
2743
|
+
*/
|
|
2744
|
+
missing(...permissions: string[]): string[];
|
|
2745
|
+
/**
|
|
2746
|
+
* Return a **new** `PermissionsBitfield` with the given permission granted.
|
|
2747
|
+
*
|
|
2748
|
+
* @example
|
|
2749
|
+
* const updated = perms.grant('channels.manage')
|
|
2750
|
+
*/
|
|
2751
|
+
grant(...permissions: string[]): PermissionsBitfield;
|
|
2752
|
+
/**
|
|
2753
|
+
* Return a **new** `PermissionsBitfield` with the given permission denied.
|
|
2754
|
+
*
|
|
2755
|
+
* @example
|
|
2756
|
+
* const restricted = perms.deny('members.kick')
|
|
2757
|
+
*/
|
|
2758
|
+
deny(...permissions: string[]): PermissionsBitfield;
|
|
2759
|
+
/**
|
|
2760
|
+
* Merge another record or `PermissionsBitfield` on top of this one.
|
|
2761
|
+
* The incoming values **override** any existing ones.
|
|
2762
|
+
*
|
|
2763
|
+
* @example
|
|
2764
|
+
* const merged = serverPerms.merge(channelOverrides)
|
|
2765
|
+
*/
|
|
2766
|
+
merge(other: Record<string, boolean> | PermissionsBitfield): PermissionsBitfield;
|
|
2767
|
+
/**
|
|
2768
|
+
* Returns an array of the permission keys that are **currently granted**.
|
|
2769
|
+
*
|
|
2770
|
+
* @example
|
|
2771
|
+
* perms.toArray() // ['messages.read', 'messages.write']
|
|
2772
|
+
*/
|
|
2773
|
+
toArray(): string[];
|
|
2774
|
+
/**
|
|
2775
|
+
* Returns the raw `Record<string, boolean>` map.
|
|
2776
|
+
*/
|
|
2777
|
+
toRecord(): Record<string, boolean>;
|
|
2778
|
+
/**
|
|
2779
|
+
* Pretty-print the granted permissions.
|
|
2780
|
+
*
|
|
2781
|
+
* @example
|
|
2782
|
+
* console.log(String(perms)) // 'PermissionsBitfield[messages.read, messages.write]'
|
|
2783
|
+
*/
|
|
2784
|
+
toString(): string;
|
|
2785
|
+
/** Create a `PermissionsBitfield` from an existing record. */
|
|
2786
|
+
static from(perms: Record<string, boolean>): PermissionsBitfield;
|
|
2787
|
+
/** A `PermissionsBitfield` with all known permissions granted. */
|
|
2788
|
+
static readonly ALL: PermissionsBitfield;
|
|
2789
|
+
/** A `PermissionsBitfield` with no permissions granted. */
|
|
2790
|
+
static readonly NONE: PermissionsBitfield;
|
|
1262
2791
|
}
|
|
1263
2792
|
|
|
1264
|
-
|
|
2793
|
+
/**
|
|
2794
|
+
* Returns a promise that resolves after `ms` milliseconds.
|
|
2795
|
+
* Useful in retry loops, cron tasks, and staged sends.
|
|
2796
|
+
*
|
|
2797
|
+
* @example
|
|
2798
|
+
* await sleep(2_000) // wait 2 seconds
|
|
2799
|
+
*/
|
|
2800
|
+
declare function sleep(ms: number): Promise<void>;
|
|
2801
|
+
/**
|
|
2802
|
+
* Wraps a promise with a timeout — rejects with an error if the original
|
|
2803
|
+
* promise does not resolve within `ms` milliseconds.
|
|
2804
|
+
*
|
|
2805
|
+
* @example
|
|
2806
|
+
* const result = await withTimeout(fetchData(), 5_000, 'fetchData took too long')
|
|
2807
|
+
*/
|
|
2808
|
+
declare function withTimeout<T>(promise: Promise<T>, ms: number, message?: string): Promise<T>;
|
|
2809
|
+
/**
|
|
2810
|
+
* Format a duration in milliseconds to a compact human-readable string.
|
|
2811
|
+
*
|
|
2812
|
+
* @example
|
|
2813
|
+
* formatDuration(0) // '0s'
|
|
2814
|
+
* formatDuration(90_000) // '1m 30s'
|
|
2815
|
+
* formatDuration(3_661_000) // '1h 1m 1s'
|
|
2816
|
+
* formatDuration(604_800_000) // '1w'
|
|
2817
|
+
*/
|
|
2818
|
+
declare function formatDuration(ms: number): string;
|
|
2819
|
+
/**
|
|
2820
|
+
* Format a timestamp as a relative human-readable string from now.
|
|
2821
|
+
* Accepts a `Date`, a Unix timestamp (ms), or an ISO date string.
|
|
2822
|
+
*
|
|
2823
|
+
* @example
|
|
2824
|
+
* formatRelative(Date.now() - 5_000) // 'just now'
|
|
2825
|
+
* formatRelative(Date.now() - 90_000) // '1 minute ago'
|
|
2826
|
+
* formatRelative(Date.now() + 60_000) // 'in 1 minute'
|
|
2827
|
+
* formatRelative(Date.now() - 86_400_000) // 'yesterday'
|
|
2828
|
+
*/
|
|
2829
|
+
declare function formatRelative(timestamp: Date | number | string): string;
|
|
2830
|
+
/**
|
|
2831
|
+
* Safely parse any timestamp (ISO string, Unix ms, or Date) to a `Date`.
|
|
2832
|
+
* Returns `null` if the input is nullish or not parseable.
|
|
2833
|
+
*
|
|
2834
|
+
* @example
|
|
2835
|
+
* parseTimestamp('2026-01-01T00:00:00.000Z') // Date
|
|
2836
|
+
* parseTimestamp(null) // null
|
|
2837
|
+
*/
|
|
2838
|
+
declare function parseTimestamp(value: string | number | Date | null | undefined): Date | null;
|
|
2839
|
+
/**
|
|
2840
|
+
* Returns the remaining time until a target date as an object with components.
|
|
2841
|
+
* All values are `0` if the target is in the past.
|
|
2842
|
+
*
|
|
2843
|
+
* @example
|
|
2844
|
+
* const { days, hours, minutes, seconds } = countdown(new Date('2027-01-01'))
|
|
2845
|
+
* console.log(`${days}d ${hours}h ${minutes}m ${seconds}s remaining`)
|
|
2846
|
+
*/
|
|
2847
|
+
declare function countdown(target: Date | number | string): {
|
|
2848
|
+
weeks: number;
|
|
2849
|
+
days: number;
|
|
2850
|
+
hours: number;
|
|
2851
|
+
minutes: number;
|
|
2852
|
+
seconds: number;
|
|
2853
|
+
total: number;
|
|
2854
|
+
};
|
|
2855
|
+
|
|
2856
|
+
export { ActionRowBuilder, type Attachment, type BanEntry, type BotApplication, type BotEvent, type BotEventType, type BotModalDefinition, type BotModalField, type BotPermissionRecord, type BotStatus, type BotUser, ButtonBuilder, type ButtonStyle, type Channel, type ChannelType, ChannelsAPI, Collection, CommandsAPI, type ContextCommandDefinition, Cooldown, CooldownManager, type CreateChannelOptions, type DirectMessage, type EditChannelOptions, type EditMessageOptions, type Embed, EmbedBuilder, type EmbedField, type FetchChannelsOptions, type FetchMembersOptions, type FetchMessagesOptions, HttpClient, type Interaction, InteractionOptions, type InteractionType, InteractionsAPI, type Invite, Logger, type Member, MembersAPI, type Message, MessageBuilder, type MessageComponent, MessagesAPI, ModalBuilder, NovaChannel, NovaClient, type NovaClientEvents, type NovaClientOptions, NovaInteraction, NovaMember, NovaMessage, type NovaServer, Paginator, type PermissionKey, Permissions, PermissionsAPI, PermissionsBitfield, type PermissionsQueryOptions, type PermissionsResult, PollBuilder, type PollDefinition, type PollInteractionsOptions, type PollOption, type PrefixCommandDefinition, type Reaction, type ReactionDetail, ReactionsAPI, type RegisteredContextCommand, type RegisteredPrefixCommand, type RegisteredSlashCommand, type RespondInteractionOptions, type Role, SelectMenuBuilder, type SelectMenuOption, type SendMessageOptions, ServersAPI, SlashCommandBuilder, type SlashCommandDefinition, type SlashCommandOption, SlashCommandOptionBuilder, TextInputBuilder, type TextInputStyle, type VoiceState, countdown, formatDuration, formatRelative, parseTimestamp, sleep, withTimeout };
|