novaapp-sdk 1.1.0 → 1.2.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 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
+ isNsfw: boolean;
72
+ slowMode: number | null;
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,24 @@ 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
+ isNsfw?: boolean;
340
+ slowMode?: number;
341
+ }
342
+ interface EditChannelOptions {
343
+ name?: string;
344
+ topic?: string;
345
+ position?: number;
346
+ isNsfw?: boolean;
347
+ slowMode?: number;
348
+ }
349
+ interface FetchChannelsOptions {
350
+ type?: ChannelType;
351
+ }
281
352
  /** A raw permission record stored for a specific scope (server, role, or channel). */
282
353
  interface BotPermissionRecord {
283
354
  id: string;
@@ -354,6 +425,64 @@ declare class MessagesAPI {
354
425
  typing(channelId: string): Promise<{
355
426
  ok: true;
356
427
  }>;
428
+ /**
429
+ * Fetch a single message by ID.
430
+ *
431
+ * @example
432
+ * const msg = await client.messages.fetchOne('message-id')
433
+ */
434
+ fetchOne(messageId: string): Promise<Message>;
435
+ /**
436
+ * Pin a message in its channel.
437
+ * The bot must have the `messages.manage` scope.
438
+ *
439
+ * @example
440
+ * await client.messages.pin('message-id')
441
+ */
442
+ pin(messageId: string): Promise<{
443
+ ok: true;
444
+ }>;
445
+ /**
446
+ * Unpin a message.
447
+ *
448
+ * @example
449
+ * await client.messages.unpin('message-id')
450
+ */
451
+ unpin(messageId: string): Promise<{
452
+ ok: true;
453
+ }>;
454
+ /**
455
+ * Fetch all pinned messages in a channel.
456
+ *
457
+ * @example
458
+ * const pins = await client.messages.fetchPinned('channel-id')
459
+ */
460
+ fetchPinned(channelId: string): Promise<Message[]>;
461
+ /**
462
+ * Add a reaction to a message.
463
+ *
464
+ * @example
465
+ * await client.messages.addReaction('message-id', '👍')
466
+ */
467
+ addReaction(messageId: string, emoji: string): Promise<{
468
+ ok: true;
469
+ }>;
470
+ /**
471
+ * Remove the bot's reaction from a message.
472
+ *
473
+ * @example
474
+ * await client.messages.removeReaction('message-id', '👍')
475
+ */
476
+ removeReaction(messageId: string, emoji: string): Promise<{
477
+ ok: true;
478
+ }>;
479
+ /**
480
+ * Fetch all reactions on a message.
481
+ *
482
+ * @example
483
+ * const reactions = await client.messages.fetchReactions('message-id')
484
+ */
485
+ fetchReactions(messageId: string): Promise<ReactionDetail[]>;
357
486
  }
358
487
 
359
488
  declare class CommandsAPI {
@@ -460,6 +589,56 @@ declare class MembersAPI {
460
589
  ban(serverId: string, userId: string, reason?: string): Promise<{
461
590
  ok: true;
462
591
  }>;
592
+ /**
593
+ * Unban a previously banned user.
594
+ * Requires the `members.ban` scope.
595
+ *
596
+ * @example
597
+ * await client.members.unban('server-id', 'user-id')
598
+ */
599
+ unban(serverId: string, userId: string): Promise<{
600
+ ok: true;
601
+ }>;
602
+ /**
603
+ * Fetch the ban list for a server.
604
+ * Requires the `members.ban` scope.
605
+ *
606
+ * @example
607
+ * const bans = await client.members.listBans('server-id')
608
+ * for (const ban of bans) {
609
+ * console.log(`${ban.username} — ${ban.reason ?? 'No reason'}`)
610
+ * }
611
+ */
612
+ listBans(serverId: string): Promise<BanEntry[]>;
613
+ /**
614
+ * Send a direct message to a user (DM).
615
+ * Requires the `messages.write` scope.
616
+ *
617
+ * @example
618
+ * await client.members.dm('user-id', { content: 'Hello!' })
619
+ * await client.members.dm('user-id', 'Hello from the bot!')
620
+ */
621
+ dm(userId: string, options: string | Omit<SendMessageOptions, 'replyToId'>): Promise<Message>;
622
+ /**
623
+ * Add a role to a member.
624
+ * Requires the `members.roles` scope.
625
+ *
626
+ * @example
627
+ * await client.members.addRole('server-id', 'user-id', 'role-id')
628
+ */
629
+ addRole(serverId: string, userId: string, roleId: string): Promise<{
630
+ ok: true;
631
+ }>;
632
+ /**
633
+ * Remove a role from a member.
634
+ * Requires the `members.roles` scope.
635
+ *
636
+ * @example
637
+ * await client.members.removeRole('server-id', 'user-id', 'role-id')
638
+ */
639
+ removeRole(serverId: string, userId: string, roleId: string): Promise<{
640
+ ok: true;
641
+ }>;
463
642
  }
464
643
 
465
644
  declare class ServersAPI {
@@ -473,6 +652,15 @@ declare class ServersAPI {
473
652
  * console.log(`Bot is in ${servers.length} servers`)
474
653
  */
475
654
  list(): Promise<NovaServer[]>;
655
+ /**
656
+ * Fetch all roles in a server.
657
+ * Results are sorted by position (lowest first).
658
+ *
659
+ * @example
660
+ * const roles = await client.servers.listRoles('server-id')
661
+ * const adminRole = roles.find(r => r.name === 'Admin')
662
+ */
663
+ listRoles(serverId: string): Promise<Role[]>;
476
664
  }
477
665
 
478
666
  declare class InteractionsAPI {
@@ -598,6 +786,144 @@ declare class PermissionsAPI {
598
786
  get(options: PermissionsQueryOptions): Promise<PermissionsResult>;
599
787
  }
600
788
 
789
+ declare class ChannelsAPI {
790
+ private readonly http;
791
+ constructor(http: HttpClient);
792
+ /**
793
+ * Fetch all channels in a server the bot is a member of.
794
+ *
795
+ * @example
796
+ * const channels = await client.channels.list('server-id')
797
+ * const textChannels = channels.filter(c => c.type === 'TEXT')
798
+ */
799
+ list(serverId: string): Promise<Channel[]>;
800
+ /**
801
+ * Fetch a single channel by ID.
802
+ *
803
+ * @example
804
+ * const channel = await client.channels.fetch('channel-id')
805
+ * console.log(channel.name, channel.type)
806
+ */
807
+ fetch(channelId: string): Promise<Channel>;
808
+ /**
809
+ * Create a new channel in a server.
810
+ * Requires the `channels.manage` scope.
811
+ *
812
+ * @example
813
+ * const channel = await client.channels.create('server-id', {
814
+ * name: 'announcements',
815
+ * type: 'ANNOUNCEMENT',
816
+ * topic: 'Official announcements only',
817
+ * })
818
+ */
819
+ create(serverId: string, options: CreateChannelOptions): Promise<Channel>;
820
+ /**
821
+ * Edit an existing channel.
822
+ * Requires the `channels.manage` scope.
823
+ *
824
+ * @example
825
+ * await client.channels.edit('channel-id', { topic: 'New topic!' })
826
+ */
827
+ edit(channelId: string, options: EditChannelOptions): Promise<Channel>;
828
+ /**
829
+ * Delete a channel.
830
+ * Requires the `channels.manage` scope.
831
+ *
832
+ * @example
833
+ * await client.channels.delete('channel-id')
834
+ */
835
+ delete(channelId: string): Promise<{
836
+ ok: true;
837
+ }>;
838
+ /**
839
+ * Fetch messages from a channel.
840
+ *
841
+ * @example
842
+ * const messages = await client.channels.fetchMessages('channel-id', { limit: 50 })
843
+ */
844
+ fetchMessages(channelId: string, options?: FetchMessagesOptions): Promise<Message[]>;
845
+ /**
846
+ * Fetch all pinned messages in a channel.
847
+ *
848
+ * @example
849
+ * const pins = await client.channels.fetchPins('channel-id')
850
+ */
851
+ fetchPins(channelId: string): Promise<Message[]>;
852
+ /**
853
+ * Send a typing indicator in a channel.
854
+ * Displayed to users for ~5 seconds.
855
+ *
856
+ * @example
857
+ * await client.channels.startTyping('channel-id')
858
+ */
859
+ startTyping(channelId: string): Promise<{
860
+ ok: true;
861
+ }>;
862
+ }
863
+
864
+ declare class ReactionsAPI {
865
+ private readonly http;
866
+ constructor(http: HttpClient);
867
+ /**
868
+ * Add a reaction to a message.
869
+ * Use a plain emoji character or a custom emoji ID.
870
+ *
871
+ * @example
872
+ * await client.reactions.add('message-id', '👍')
873
+ * await client.reactions.add('message-id', '🎉')
874
+ */
875
+ add(messageId: string, emoji: string): Promise<{
876
+ ok: true;
877
+ }>;
878
+ /**
879
+ * Remove the bot's reaction from a message.
880
+ *
881
+ * @example
882
+ * await client.reactions.remove('message-id', '👍')
883
+ */
884
+ remove(messageId: string, emoji: string): Promise<{
885
+ ok: true;
886
+ }>;
887
+ /**
888
+ * Remove all reactions from a message.
889
+ * Requires the `messages.manage` scope.
890
+ *
891
+ * @example
892
+ * await client.reactions.removeAll('message-id')
893
+ */
894
+ removeAll(messageId: string): Promise<{
895
+ ok: true;
896
+ }>;
897
+ /**
898
+ * Remove all reactions of a specific emoji from a message.
899
+ * Requires the `messages.manage` scope.
900
+ *
901
+ * @example
902
+ * await client.reactions.removeEmoji('message-id', '👍')
903
+ */
904
+ removeEmoji(messageId: string, emoji: string): Promise<{
905
+ ok: true;
906
+ }>;
907
+ /**
908
+ * Fetch all reactions on a message, broken down by emoji.
909
+ *
910
+ * @example
911
+ * const reactions = await client.reactions.fetch('message-id')
912
+ * for (const r of reactions) {
913
+ * console.log(`${r.emoji} — ${r.count} reactions from ${r.users.map(u => u.username).join(', ')}`)
914
+ * }
915
+ */
916
+ fetch(messageId: string): Promise<ReactionDetail[]>;
917
+ /**
918
+ * Fetch reactions for a specific emoji on a message.
919
+ *
920
+ * @example
921
+ * const detail = await client.reactions.fetchEmoji('message-id', '👍')
922
+ * console.log(`${detail.count} thumbs ups`)
923
+ */
924
+ fetchEmoji(messageId: string, emoji: string): Promise<ReactionDetail>;
925
+ }
926
+
601
927
  type TextInputStyle = 'short' | 'paragraph';
602
928
  /**
603
929
  * Fluent builder for a single text-input field inside a modal.
@@ -878,6 +1204,135 @@ declare class NovaInteraction {
878
1204
  toJSON(): Interaction;
879
1205
  }
880
1206
 
1207
+ /**
1208
+ * A rich wrapper around a raw `Message` with convenience methods.
1209
+ *
1210
+ * Returned by `client.on('messageCreate', ...)` and from message fetch calls.
1211
+ *
1212
+ * @example
1213
+ * client.on('messageCreate', async (msg) => {
1214
+ * if (msg.content.toLowerCase() === '!ping') {
1215
+ * await msg.reply('Pong! 🏓')
1216
+ * await msg.react('🏓')
1217
+ * }
1218
+ * })
1219
+ */
1220
+ declare class NovaMessage {
1221
+ /** The raw message ID. */
1222
+ readonly id: string;
1223
+ /** The message text content. */
1224
+ readonly content: string;
1225
+ /** The channel this message was sent in. */
1226
+ readonly channelId: string;
1227
+ /** The author of the message. */
1228
+ readonly author: Message['author'];
1229
+ /** Embed attached to this message, if any. */
1230
+ readonly embed: Embed | null;
1231
+ /** Interactive components (buttons, selects) attached to this message. */
1232
+ readonly components: MessageComponent[];
1233
+ /** The message this is replying to, if any. */
1234
+ readonly replyToId: string | null;
1235
+ /** Uploaded file attachments. */
1236
+ readonly attachments: Attachment[];
1237
+ /** Reactions on this message. */
1238
+ readonly reactions: Reaction[];
1239
+ /** When the message was sent. */
1240
+ readonly createdAt: Date;
1241
+ /** When the message was last edited, or `null`. */
1242
+ readonly editedAt: Date | null;
1243
+ private readonly _messages;
1244
+ private readonly _reactions;
1245
+ constructor(raw: Message, messages: MessagesAPI, reactions: ReactionsAPI);
1246
+ /** Returns true if the message was sent by a bot. */
1247
+ isFromBot(): boolean;
1248
+ /** Returns true if the message has an embed. */
1249
+ hasEmbed(): boolean;
1250
+ /** Returns true if the message has interactive components. */
1251
+ hasComponents(): boolean;
1252
+ /** Returns true if the message has been edited. */
1253
+ isEdited(): boolean;
1254
+ /**
1255
+ * Add a reaction to this message.
1256
+ *
1257
+ * @example
1258
+ * await msg.react('👍')
1259
+ * await msg.react('🎉')
1260
+ */
1261
+ react(emoji: string): Promise<{
1262
+ ok: true;
1263
+ }>;
1264
+ /**
1265
+ * Remove the bot's reaction from this message.
1266
+ *
1267
+ * @example
1268
+ * await msg.removeReaction('👍')
1269
+ */
1270
+ removeReaction(emoji: string): Promise<{
1271
+ ok: true;
1272
+ }>;
1273
+ /**
1274
+ * Reply to this message.
1275
+ *
1276
+ * @example
1277
+ * await msg.reply('Got it!')
1278
+ * await msg.reply({ embed: new EmbedBuilder().setTitle('Result').toJSON() })
1279
+ */
1280
+ reply(options: string | Omit<SendMessageOptions, 'replyToId'>): Promise<NovaMessage>;
1281
+ /**
1282
+ * Edit this message.
1283
+ * Only works if the bot is the author.
1284
+ *
1285
+ * @example
1286
+ * await msg.edit('Updated content')
1287
+ * await msg.edit({ content: 'Updated', embed: { title: 'New embed' } })
1288
+ */
1289
+ edit(options: string | EditMessageOptions): Promise<NovaMessage>;
1290
+ /**
1291
+ * Delete this message.
1292
+ * Only works if the bot is the author.
1293
+ *
1294
+ * @example
1295
+ * await msg.delete()
1296
+ */
1297
+ delete(): Promise<{
1298
+ ok: true;
1299
+ }>;
1300
+ /**
1301
+ * Pin this message in its channel.
1302
+ *
1303
+ * @example
1304
+ * await msg.pin()
1305
+ */
1306
+ pin(): Promise<{
1307
+ ok: true;
1308
+ }>;
1309
+ /**
1310
+ * Unpin this message.
1311
+ *
1312
+ * @example
1313
+ * await msg.unpin()
1314
+ */
1315
+ unpin(): Promise<{
1316
+ ok: true;
1317
+ }>;
1318
+ /**
1319
+ * Re-fetch the latest version of this message from the server.
1320
+ *
1321
+ * @example
1322
+ * const fresh = await msg.fetch()
1323
+ */
1324
+ fetch(): Promise<NovaMessage>;
1325
+ /**
1326
+ * Get a URL to this message (deep link).
1327
+ */
1328
+ get url(): string;
1329
+ /**
1330
+ * Return the raw message object.
1331
+ */
1332
+ toJSON(): Message;
1333
+ toString(): string;
1334
+ }
1335
+
881
1336
  interface NovaClientEvents {
882
1337
  /** Fired when the bot connects and is identified by the gateway. */
883
1338
  ready: (bot: BotApplication) => void;
@@ -897,21 +1352,50 @@ interface NovaClientEvents {
897
1352
  message: string;
898
1353
  }) => void;
899
1354
  /** 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;
1355
+ messageCreate: (message: NovaMessage) => void;
1356
+ /** A message was edited. Returns the updated message. */
1357
+ messageUpdate: (message: NovaMessage) => void;
1358
+ /** A message was deleted. Returns partial data. */
1359
+ messageDelete: (data: {
1360
+ id: string;
1361
+ channelId: string;
1362
+ }) => void;
1363
+ /** A reaction was added to a message. */
1364
+ reactionAdd: (data: {
1365
+ messageId: string;
1366
+ channelId: string;
1367
+ userId: string;
1368
+ emoji: string;
1369
+ }) => void;
1370
+ /** A reaction was removed from a message. */
1371
+ reactionRemove: (data: {
1372
+ messageId: string;
1373
+ channelId: string;
1374
+ userId: string;
1375
+ emoji: string;
1376
+ }) => void;
909
1377
  /** A member joined a server the bot is in. */
910
- memberAdd: (data: BotEvent['data']) => void;
1378
+ memberAdd: (data: {
1379
+ serverId: string;
1380
+ userId: string;
1381
+ username: string;
1382
+ }) => void;
911
1383
  /** 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;
1384
+ memberRemove: (data: {
1385
+ serverId: string;
1386
+ userId: string;
1387
+ }) => void;
1388
+ /** A user started typing in a channel. */
1389
+ typingStart: (data: {
1390
+ channelId: string;
1391
+ userId: string;
1392
+ }) => void;
1393
+ /** A message was pinned. */
1394
+ messagePinned: (data: {
1395
+ messageId: string;
1396
+ channelId: string;
1397
+ pinnedBy: string;
1398
+ }) => void;
915
1399
  }
916
1400
  /**
917
1401
  * The main Nova bot client.
@@ -948,9 +1432,14 @@ declare class NovaClient extends EventEmitter {
948
1432
  readonly interactions: InteractionsAPI;
949
1433
  /** Query the bot's effective permissions within a server, channel, or role scope. */
950
1434
  readonly permissions: PermissionsAPI;
1435
+ /** Create, edit, and delete channels; fetch pins and messages. */
1436
+ readonly channels: ChannelsAPI;
1437
+ /** Add, remove and fetch reactions on messages. */
1438
+ readonly reactions: ReactionsAPI;
951
1439
  private socket;
952
1440
  private readonly http;
953
1441
  private readonly options;
1442
+ private _cronTimers;
954
1443
  private readonly _commandHandlers;
955
1444
  private readonly _buttonHandlers;
956
1445
  private readonly _selectHandlers;
@@ -992,6 +1481,33 @@ declare class NovaClient extends EventEmitter {
992
1481
  * await client.connect()
993
1482
  */
994
1483
  connect(): Promise<void>;
1484
+ /**
1485
+ * Register a recurring task that fires at a set interval.
1486
+ * All cron tasks are automatically cancelled on `disconnect()`.
1487
+ *
1488
+ * @param intervalMs - How often to run the task (in milliseconds).
1489
+ * @param fn - Async or sync function to call on each tick.
1490
+ * @returns A cancel function — call it to stop this specific task.
1491
+ *
1492
+ * @example
1493
+ * // Check for new announcements every 30 seconds
1494
+ * client.cron(30_000, async () => {
1495
+ * const messages = await client.messages.fetch(channelId, { limit: 5 })
1496
+ * // do something...
1497
+ * })
1498
+ */
1499
+ cron(intervalMs: number, fn: () => unknown): () => void;
1500
+ /**
1501
+ * Set the bot's presence status.
1502
+ * Broadcasts to all servers the bot is in via WebSocket.
1503
+ *
1504
+ * @example
1505
+ * client.setStatus('DND') // Do Not Disturb
1506
+ * client.setStatus('IDLE') // Away
1507
+ * client.setStatus('OFFLINE') // Appear offline
1508
+ * client.setStatus('ONLINE') // Back online
1509
+ */
1510
+ setStatus(status: BotStatus): void;
995
1511
  /**
996
1512
  * Disconnect from the gateway and clean up.
997
1513
  */
@@ -1261,4 +1777,475 @@ declare class SlashCommandBuilder {
1261
1777
  toJSON(): SlashCommandDefinition;
1262
1778
  }
1263
1779
 
1264
- export { ActionRowBuilder, type Attachment, type BotApplication, type BotEvent, type BotEventType, type BotModalDefinition, type BotModalField, type BotPermissionRecord, type BotUser, ButtonBuilder, type ButtonStyle, CommandsAPI, type ContextCommandDefinition, type EditMessageOptions, type Embed, EmbedBuilder, type EmbedField, type FetchMembersOptions, type FetchMessagesOptions, HttpClient, type Interaction, InteractionOptions, type InteractionType, InteractionsAPI, type Member, MembersAPI, type Message, type MessageComponent, MessagesAPI, ModalBuilder, NovaClient, type NovaClientEvents, type NovaClientOptions, NovaInteraction, type NovaServer, PermissionsAPI, type PermissionsQueryOptions, type PermissionsResult, type PollInteractionsOptions, type PrefixCommandDefinition, type Reaction, type RegisteredContextCommand, type RegisteredPrefixCommand, type RegisteredSlashCommand, type RespondInteractionOptions, SelectMenuBuilder, type SelectMenuOption, type SendMessageOptions, ServersAPI, SlashCommandBuilder, type SlashCommandDefinition, type SlashCommandOption, SlashCommandOptionBuilder, TextInputBuilder, type TextInputStyle };
1780
+ interface PollOption {
1781
+ label: string;
1782
+ emoji?: string;
1783
+ value?: string;
1784
+ }
1785
+ interface PollDefinition {
1786
+ question: string;
1787
+ options: PollOption[];
1788
+ allowMultiple?: boolean;
1789
+ duration?: number | null;
1790
+ anonymous?: boolean;
1791
+ }
1792
+ /**
1793
+ * Fluent builder for creating polls.
1794
+ *
1795
+ * @example
1796
+ * const poll = new PollBuilder()
1797
+ * .setQuestion('What is your favourite colour?')
1798
+ * .addOption({ label: 'Red', emoji: '🔴' })
1799
+ * .addOption({ label: 'Green', emoji: '🟢' })
1800
+ * .addOption({ label: 'Blue', emoji: '🔵' })
1801
+ * .setDuration(60 * 60 * 24) // 24 hours in seconds
1802
+ * .toJSON()
1803
+ *
1804
+ * await client.messages.send(channelId, { poll })
1805
+ */
1806
+ declare class PollBuilder {
1807
+ private _question;
1808
+ private _options;
1809
+ private _allowMultiple;
1810
+ private _duration;
1811
+ private _anonymous;
1812
+ /**
1813
+ * Set the poll question.
1814
+ *
1815
+ * @example
1816
+ * builder.setQuestion('Best programming language?')
1817
+ */
1818
+ setQuestion(question: string): this;
1819
+ /**
1820
+ * Add a single answer option.
1821
+ *
1822
+ * @example
1823
+ * builder.addOption({ label: 'TypeScript', emoji: '🔷' })
1824
+ */
1825
+ addOption(option: PollOption): this;
1826
+ /**
1827
+ * Add multiple answer options at once.
1828
+ *
1829
+ * @example
1830
+ * builder.addOptions([
1831
+ * { label: 'Yes', emoji: '✅' },
1832
+ * { label: 'No', emoji: '❌' },
1833
+ * ])
1834
+ */
1835
+ addOptions(options: PollOption[]): this;
1836
+ /**
1837
+ * Allow users to select more than one option.
1838
+ * Default: `false` (single choice).
1839
+ */
1840
+ setAllowMultiple(yes?: boolean): this;
1841
+ /**
1842
+ * Set the poll duration in **seconds**. Pass `null` to make it permanent.
1843
+ *
1844
+ * @example
1845
+ * builder.setDuration(60 * 60 * 24) // expires in 24 hours
1846
+ * builder.setDuration(null) // no expiry
1847
+ */
1848
+ setDuration(seconds: number | null): this;
1849
+ /**
1850
+ * Hide which users voted for which option.
1851
+ * Default: `false` (votes are public).
1852
+ */
1853
+ setAnonymous(yes?: boolean): this;
1854
+ /** Build the poll definition object. */
1855
+ toJSON(): PollDefinition;
1856
+ }
1857
+
1858
+ /**
1859
+ * Fluent builder for composing messages.
1860
+ * Replaces passing raw option objects everywhere.
1861
+ *
1862
+ * @example
1863
+ * const msg = new MessageBuilder()
1864
+ * .setContent('Here are your stats:')
1865
+ * .setEmbed(
1866
+ * new EmbedBuilder()
1867
+ * .setTitle('📊 Stats')
1868
+ * .addField('Messages', '1 234', true)
1869
+ * .addField('Reactions', '567', true)
1870
+ * .setColor('#5865F2')
1871
+ * )
1872
+ * .addRow(
1873
+ * new ActionRowBuilder()
1874
+ * .addComponent(new ButtonBuilder().setLabel('Refresh').setCustomId('refresh').setStyle('primary'))
1875
+ * )
1876
+ * .toJSON()
1877
+ *
1878
+ * await client.messages.send(channelId, msg)
1879
+ */
1880
+ declare class MessageBuilder {
1881
+ private _content;
1882
+ private _embed;
1883
+ private _components;
1884
+ private _replyToId;
1885
+ private _poll;
1886
+ /**
1887
+ * Set the text content of the message.
1888
+ *
1889
+ * @example
1890
+ * builder.setContent('Hello world!')
1891
+ */
1892
+ setContent(content: string): this;
1893
+ /**
1894
+ * Attach an embed. Accepts an `EmbedBuilder` or raw `Embed` object.
1895
+ *
1896
+ * @example
1897
+ * builder.setEmbed(new EmbedBuilder().setTitle('Result'))
1898
+ * builder.setEmbed({ title: 'Result', color: '#57F287' })
1899
+ */
1900
+ setEmbed(embed: EmbedBuilder | Embed): this;
1901
+ /**
1902
+ * Remove any embed from this message.
1903
+ */
1904
+ clearEmbed(): this;
1905
+ /**
1906
+ * Add an `ActionRowBuilder` (or raw component array) as a component row.
1907
+ *
1908
+ * @example
1909
+ * builder.addRow(
1910
+ * new ActionRowBuilder().addComponent(btn1).addComponent(btn2)
1911
+ * )
1912
+ */
1913
+ addRow(row: ActionRowBuilder | MessageComponent[]): this;
1914
+ /**
1915
+ * Replace all existing component rows.
1916
+ */
1917
+ setComponents(components: MessageComponent[]): this;
1918
+ /**
1919
+ * Set the message this is replying to.
1920
+ *
1921
+ * @example
1922
+ * builder.setReplyTo(message.id)
1923
+ */
1924
+ setReplyTo(messageId: string): this;
1925
+ /**
1926
+ * Attach a poll to the message.
1927
+ * Accepts a `PollBuilder` or raw `PollDefinition`.
1928
+ *
1929
+ * @example
1930
+ * builder.setPoll(
1931
+ * new PollBuilder()
1932
+ * .setQuestion('Favourite language?')
1933
+ * .addOptions([{ label: 'TypeScript' }, { label: 'Python' }])
1934
+ * )
1935
+ */
1936
+ setPoll(poll: {
1937
+ toJSON: () => PollDefinition;
1938
+ } | PollDefinition): this;
1939
+ /**
1940
+ * Build the message options object, ready to pass to `client.messages.send()`.
1941
+ *
1942
+ * @throws if neither `content` nor `embed` nor `poll` is set.
1943
+ */
1944
+ toJSON(): SendMessageOptions & {
1945
+ poll?: PollDefinition;
1946
+ };
1947
+ }
1948
+
1949
+ /**
1950
+ * A supercharged Map with extra utility methods.
1951
+ * Used throughout the SDK for caches (messages, channels, members, etc.)
1952
+ *
1953
+ * Inspired by discord.js Collection — but with proper generics and async support.
1954
+ *
1955
+ * @example
1956
+ * const col = new Collection<string, User>()
1957
+ * col.set('u1', { id: 'u1', name: 'Alice' })
1958
+ * col.set('u2', { id: 'u2', name: 'Bob' })
1959
+ *
1960
+ * col.first() // { id: 'u1', name: 'Alice' }
1961
+ * col.find(u => u.name === 'Bob') // { id: 'u2', name: 'Bob' }
1962
+ * col.map(u => u.name) // ['Alice', 'Bob']
1963
+ */
1964
+ declare class Collection<K, V> extends Map<K, V> {
1965
+ /**
1966
+ * The first value stored (insertion order), or `undefined` if empty.
1967
+ */
1968
+ first(): V | undefined;
1969
+ /**
1970
+ * The first `n` values stored (insertion order).
1971
+ */
1972
+ firstN(n: number): V[];
1973
+ /**
1974
+ * The last value stored, or `undefined` if empty.
1975
+ */
1976
+ last(): V | undefined;
1977
+ /**
1978
+ * The last `n` values stored (insertion order).
1979
+ */
1980
+ lastN(n: number): V[];
1981
+ /**
1982
+ * Returns a random value from the collection, or `undefined` if empty.
1983
+ */
1984
+ random(): V | undefined;
1985
+ /**
1986
+ * Find the first value that passes the predicate.
1987
+ *
1988
+ * @example
1989
+ * const bot = members.find(m => m.user.isBot)
1990
+ */
1991
+ find(fn: (value: V, key: K, col: this) => boolean): V | undefined;
1992
+ /**
1993
+ * Find the key of the first value that passes the predicate.
1994
+ */
1995
+ findKey(fn: (value: V, key: K, col: this) => boolean): K | undefined;
1996
+ /**
1997
+ * Returns `true` if at least one value satisfies the predicate.
1998
+ */
1999
+ some(fn: (value: V, key: K, col: this) => boolean): boolean;
2000
+ /**
2001
+ * Returns `true` if every value satisfies the predicate.
2002
+ */
2003
+ every(fn: (value: V, key: K, col: this) => boolean): boolean;
2004
+ /**
2005
+ * Filter to a new Collection containing only values that pass the predicate.
2006
+ *
2007
+ * @example
2008
+ * const admins = members.filter(m => m.role === 'ADMIN')
2009
+ */
2010
+ filter(fn: (value: V, key: K, col: this) => boolean): Collection<K, V>;
2011
+ /**
2012
+ * Map each value to a new array.
2013
+ *
2014
+ * @example
2015
+ * const names = members.map(m => m.user.username)
2016
+ */
2017
+ map<T>(fn: (value: V, key: K, col: this) => T): T[];
2018
+ /**
2019
+ * Map to a new Collection with transformed values.
2020
+ *
2021
+ * @example
2022
+ * const names = channels.mapValues(c => c.name.toUpperCase())
2023
+ */
2024
+ mapValues<T>(fn: (value: V, key: K, col: this) => T): Collection<K, T>;
2025
+ /**
2026
+ * Reduce the collection to a single value.
2027
+ *
2028
+ * @example
2029
+ * const totalReactions = messages.reduce((sum, m) => sum + m.reactions.length, 0)
2030
+ */
2031
+ reduce<T>(fn: (accumulator: T, value: V, key: K, col: this) => T, initial: T): T;
2032
+ /**
2033
+ * Returns values as an array (insertion order).
2034
+ */
2035
+ toArray(): V[];
2036
+ /**
2037
+ * Returns keys as an array (insertion order).
2038
+ */
2039
+ keyArray(): K[];
2040
+ /**
2041
+ * Sort and return a new Collection.
2042
+ * Callback works like `Array.prototype.sort`.
2043
+ *
2044
+ * @example
2045
+ * const sorted = channels.sort((a, b) => a.position - b.position)
2046
+ */
2047
+ sort(fn?: (a: V, b: V, ak: K, bk: K) => number): Collection<K, V>;
2048
+ /**
2049
+ * Split into two Collections based on a predicate.
2050
+ * Returns `[passing, failing]`.
2051
+ *
2052
+ * @example
2053
+ * const [bots, humans] = members.partition(m => m.user.isBot)
2054
+ */
2055
+ partition(fn: (value: V, key: K, col: this) => boolean): [Collection<K, V>, Collection<K, V>];
2056
+ /**
2057
+ * Merge this collection with one or more others.
2058
+ * Later collections overwrite duplicate keys.
2059
+ */
2060
+ merge(...others: ReadonlyMap<K, V>[]): Collection<K, V>;
2061
+ /**
2062
+ * Serialize to a plain `Record` (requires string keys).
2063
+ */
2064
+ toJSON(): Record<string, V>;
2065
+ toString(): string;
2066
+ }
2067
+
2068
+ /**
2069
+ * Per-user cooldown manager.
2070
+ * Prevents commands from being spammed by individual users.
2071
+ *
2072
+ * @example
2073
+ * // Create once per command
2074
+ * const cooldown = new Cooldown(5_000) // 5 second cooldown
2075
+ *
2076
+ * client.command('daily', async (interaction) => {
2077
+ * const remaining = cooldown.check(interaction.userId)
2078
+ * if (remaining > 0) {
2079
+ * return interaction.replyEphemeral(
2080
+ * `⏳ Wait **${Cooldown.format(remaining)}** before using this command again.`
2081
+ * )
2082
+ * }
2083
+ * cooldown.use(interaction.userId)
2084
+ * await interaction.reply('🎁 Daily reward collected!')
2085
+ * })
2086
+ */
2087
+ declare class Cooldown {
2088
+ private readonly _durations;
2089
+ private readonly _last;
2090
+ private readonly _defaultMs;
2091
+ /**
2092
+ * @param durationMs - Default cooldown duration in milliseconds.
2093
+ */
2094
+ constructor(durationMs: number);
2095
+ /**
2096
+ * Check remaining cooldown for a user.
2097
+ * Returns `0` if they are not on cooldown (free to proceed),
2098
+ * or the **milliseconds remaining** if they are on cooldown.
2099
+ *
2100
+ * @example
2101
+ * const ms = cooldown.check(userId)
2102
+ * if (ms > 0) return interaction.replyEphemeral(`Wait ${Cooldown.format(ms)}!`)
2103
+ */
2104
+ check(userId: string): number;
2105
+ /**
2106
+ * Mark a user as having just used the command, starting their cooldown.
2107
+ * Optionally override the cooldown duration for this specific user.
2108
+ *
2109
+ * @example
2110
+ * cooldown.use(userId) // uses default duration
2111
+ * cooldown.use(userId, 10_000) // 10 second cooldown for this use
2112
+ */
2113
+ use(userId: string, durationMs?: number): void;
2114
+ /**
2115
+ * Immediately reset (clear) the cooldown for a user.
2116
+ *
2117
+ * @example
2118
+ * cooldown.reset(userId) // user can use the command again immediately
2119
+ */
2120
+ reset(userId: string): void;
2121
+ /**
2122
+ * Reset all active cooldowns.
2123
+ */
2124
+ resetAll(): void;
2125
+ /**
2126
+ * Returns a list of all users currently on cooldown.
2127
+ *
2128
+ * @example
2129
+ * const active = cooldown.activeCooldowns()
2130
+ * // [{ userId: 'abc', remainingMs: 3200 }, ...]
2131
+ */
2132
+ activeCooldowns(): Array<{
2133
+ userId: string;
2134
+ remainingMs: number;
2135
+ }>;
2136
+ /**
2137
+ * Format milliseconds into a human-readable string.
2138
+ *
2139
+ * @example
2140
+ * Cooldown.format(3_600_000) // '1h 0m 0s'
2141
+ * Cooldown.format(90_000) // '1m 30s'
2142
+ * Cooldown.format(4_000) // '4s'
2143
+ */
2144
+ static format(ms: number): string;
2145
+ }
2146
+ /**
2147
+ * Manages multiple named cooldowns in one place.
2148
+ * Ideal when you have many commands each with their own cooldown.
2149
+ *
2150
+ * @example
2151
+ * const cooldowns = new CooldownManager()
2152
+ *
2153
+ * client.command('ping', async (interaction) => {
2154
+ * const remaining = cooldowns.check('ping', interaction.userId, 3_000)
2155
+ * if (remaining > 0) return interaction.replyEphemeral(`Wait ${Cooldown.format(remaining)}!`)
2156
+ * await interaction.reply('Pong!')
2157
+ * })
2158
+ */
2159
+ declare class CooldownManager {
2160
+ private readonly _map;
2161
+ /**
2162
+ * Get or create a named cooldown.
2163
+ */
2164
+ get(name: string, durationMs?: number): Cooldown;
2165
+ /**
2166
+ * Check a named cooldown for a user.
2167
+ * Creates the cooldown if it doesn't exist yet.
2168
+ * Returns `0` if free, or remaining ms if on cooldown.
2169
+ *
2170
+ * @example
2171
+ * const ms = cooldowns.check('ban', userId, 30_000)
2172
+ */
2173
+ check(name: string, userId: string, durationMs?: number): number;
2174
+ /**
2175
+ * Mark a user as having used a named command.
2176
+ *
2177
+ * @example
2178
+ * cooldowns.use('ban', userId, 30_000)
2179
+ */
2180
+ use(name: string, userId: string, durationMs?: number): void;
2181
+ /**
2182
+ * Reset a user's cooldown on a named command.
2183
+ */
2184
+ reset(name: string, userId: string): void;
2185
+ /**
2186
+ * Reset all cooldowns for all commands.
2187
+ */
2188
+ resetAll(): void;
2189
+ }
2190
+
2191
+ /**
2192
+ * Coloured, timestamped logger for Nova bots.
2193
+ * Prefix every log with a consistent `[BotName]` tag.
2194
+ *
2195
+ * @example
2196
+ * const log = new Logger('MyBot')
2197
+ * log.info('Ready!') // [MyBot] [INFO] Ready!
2198
+ * log.warn('Rate limited') // [MyBot] [WARN] Rate limited
2199
+ * log.error('DB timed out') // [MyBot] [ERROR] DB timed out
2200
+ * log.debug('Payload:', data) // [MyBot] [DEBUG] Payload: { ... }
2201
+ * log.success('Command registered') // [MyBot] [OK] Command registered
2202
+ * log.command('ping', userId) // [MyBot] [CMD] ping ← userId
2203
+ * log.event('messageCreate') // [MyBot] [EVT] messageCreate
2204
+ */
2205
+ declare class Logger {
2206
+ private readonly _prefix;
2207
+ private _debug;
2208
+ /**
2209
+ * @param name - Name shown in square brackets before every message.
2210
+ * @param enableDebug - When `false` (default), `.debug()` calls are silent.
2211
+ */
2212
+ constructor(name: string, enableDebug?: boolean);
2213
+ /** Enable or disable debug output at runtime. */
2214
+ setDebug(enabled: boolean): this;
2215
+ private _timestamp;
2216
+ private _fmt;
2217
+ /** General info message. */
2218
+ info(...args: unknown[]): void;
2219
+ /** Warning — something unexpected but non-fatal. */
2220
+ warn(...args: unknown[]): void;
2221
+ /** Error — something went wrong. */
2222
+ error(...args: unknown[]): void;
2223
+ /** Success / positive confirmation. */
2224
+ success(...args: unknown[]): void;
2225
+ /** Debug — only printed when `enableDebug` is true. */
2226
+ debug(...args: unknown[]): void;
2227
+ /**
2228
+ * Log an incoming command interaction.
2229
+ *
2230
+ * @example
2231
+ * log.command('ping', interaction.userId)
2232
+ * // [MyBot] [CMD] /ping ← user:abc123
2233
+ */
2234
+ command(name: string, userId: string): void;
2235
+ /**
2236
+ * Log a gateway event.
2237
+ *
2238
+ * @example
2239
+ * log.event('messageCreate')
2240
+ */
2241
+ event(type: string, extra?: string): void;
2242
+ /**
2243
+ * Log that a command handler threw an error.
2244
+ *
2245
+ * @example
2246
+ * log.commandError('ban', err)
2247
+ */
2248
+ commandError(name: string, err: unknown): void;
2249
+ }
2250
+
2251
+ 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 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, NovaClient, type NovaClientEvents, type NovaClientOptions, NovaInteraction, NovaMessage, type NovaServer, PermissionsAPI, 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 };