novaapp-sdk 1.4.0 → 1.4.1
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 +2378 -138
- package/dist/index.d.ts +2378 -138
- package/dist/index.js +2551 -38
- package/dist/index.mjs +2525 -38
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21,44 +21,70 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
ActionRowBuilder: () => ActionRowBuilder,
|
|
24
|
+
ArgumentParser: () => ArgumentParser,
|
|
24
25
|
AuditLogAPI: () => AuditLogAPI,
|
|
26
|
+
AutoModAPI: () => AutoModAPI,
|
|
27
|
+
AutoModRuleBuilder: () => AutoModRuleBuilder,
|
|
25
28
|
ButtonBuilder: () => ButtonBuilder,
|
|
29
|
+
CacheMap: () => CacheMap,
|
|
30
|
+
CategoriesAPI: () => CategoriesAPI,
|
|
31
|
+
ChannelBuilder: () => ChannelBuilder,
|
|
26
32
|
ChannelsAPI: () => ChannelsAPI,
|
|
27
33
|
Collection: () => Collection,
|
|
28
34
|
CommandsAPI: () => CommandsAPI,
|
|
35
|
+
ConfirmationDialog: () => ConfirmationDialog,
|
|
36
|
+
ContextMenuCommandBuilder: () => ContextMenuCommandBuilder,
|
|
29
37
|
Cooldown: () => Cooldown,
|
|
30
38
|
CooldownManager: () => CooldownManager,
|
|
31
39
|
EmbedBuilder: () => EmbedBuilder,
|
|
40
|
+
EmbedPaginator: () => EmbedPaginator,
|
|
41
|
+
EventBuilder: () => EventBuilder,
|
|
42
|
+
EventScheduler: () => EventScheduler,
|
|
43
|
+
EventsAPI: () => EventsAPI,
|
|
44
|
+
ForumAPI: () => ForumAPI,
|
|
45
|
+
ForumPostBuilder: () => ForumPostBuilder,
|
|
32
46
|
HttpClient: () => HttpClient,
|
|
47
|
+
InteractionCollector: () => InteractionCollector,
|
|
33
48
|
InteractionOptions: () => InteractionOptions,
|
|
34
49
|
InteractionsAPI: () => InteractionsAPI,
|
|
50
|
+
InviteBuilder: () => InviteBuilder,
|
|
35
51
|
InvitesAPI: () => InvitesAPI,
|
|
36
52
|
Logger: () => Logger,
|
|
37
53
|
MembersAPI: () => MembersAPI,
|
|
54
|
+
MentionParser: () => MentionParser,
|
|
38
55
|
MessageBuilder: () => MessageBuilder,
|
|
56
|
+
MessageCollector: () => MessageCollector,
|
|
39
57
|
MessagesAPI: () => MessagesAPI,
|
|
40
58
|
ModalBuilder: () => ModalBuilder,
|
|
59
|
+
NovaBan: () => NovaBan,
|
|
60
|
+
NovaCategory: () => NovaCategory,
|
|
41
61
|
NovaChannel: () => NovaChannel,
|
|
42
62
|
NovaClient: () => NovaClient,
|
|
63
|
+
NovaForumPost: () => NovaForumPost,
|
|
43
64
|
NovaInteraction: () => NovaInteraction,
|
|
44
65
|
NovaInvite: () => NovaInvite,
|
|
45
66
|
NovaMember: () => NovaMember,
|
|
46
67
|
NovaMessage: () => NovaMessage,
|
|
47
68
|
NovaRole: () => NovaRole,
|
|
69
|
+
NovaServerEvent: () => NovaServerEvent,
|
|
48
70
|
NovaServerWrapper: () => NovaServerWrapper,
|
|
71
|
+
NovaWarning: () => NovaWarning,
|
|
49
72
|
NovaWebhook: () => NovaWebhook,
|
|
50
73
|
Paginator: () => Paginator,
|
|
74
|
+
ParsedArguments: () => ParsedArguments,
|
|
51
75
|
Permissions: () => Permissions,
|
|
52
76
|
PermissionsAPI: () => PermissionsAPI,
|
|
53
77
|
PermissionsBitfield: () => PermissionsBitfield,
|
|
54
78
|
PollBuilder: () => PollBuilder,
|
|
55
79
|
ReactionsAPI: () => ReactionsAPI,
|
|
80
|
+
RoleBuilder: () => RoleBuilder,
|
|
56
81
|
RolesAPI: () => RolesAPI,
|
|
57
82
|
SelectMenuBuilder: () => SelectMenuBuilder,
|
|
58
83
|
ServersAPI: () => ServersAPI,
|
|
59
84
|
SlashCommandBuilder: () => SlashCommandBuilder,
|
|
60
85
|
SlashCommandOptionBuilder: () => SlashCommandOptionBuilder,
|
|
61
86
|
TextInputBuilder: () => TextInputBuilder,
|
|
87
|
+
UsersAPI: () => UsersAPI,
|
|
62
88
|
WebhooksAPI: () => WebhooksAPI,
|
|
63
89
|
countdown: () => countdown,
|
|
64
90
|
formatDuration: () => formatDuration,
|
|
@@ -426,6 +452,74 @@ var MembersAPI = class {
|
|
|
426
452
|
removeRole(serverId, userId, roleId) {
|
|
427
453
|
return this.http.delete(`/servers/${serverId}/members/${userId}/roles/${roleId}`);
|
|
428
454
|
}
|
|
455
|
+
/**
|
|
456
|
+
* Issue a warning to a member.
|
|
457
|
+
* Requires the `members.moderate` scope.
|
|
458
|
+
*
|
|
459
|
+
* @example
|
|
460
|
+
* await client.members.warn('server-id', 'user-id', 'Spamming')
|
|
461
|
+
*/
|
|
462
|
+
warn(serverId, userId, reason) {
|
|
463
|
+
return this.http.post(`/servers/${serverId}/members/${userId}/warn`, { reason });
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Fetch warnings for a server (or optionally a specific user).
|
|
467
|
+
* Requires the `members.moderate` scope.
|
|
468
|
+
*
|
|
469
|
+
* @example
|
|
470
|
+
* const all = await client.members.fetchWarnings('server-id')
|
|
471
|
+
* const userWarnings = await client.members.fetchWarnings('server-id', { userId: 'user-id' })
|
|
472
|
+
*/
|
|
473
|
+
fetchWarnings(serverId, options = {}) {
|
|
474
|
+
const params = new URLSearchParams();
|
|
475
|
+
if (options.userId) params.set("userId", options.userId);
|
|
476
|
+
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
477
|
+
return this.http.get(`/servers/${serverId}/warnings${qs}`);
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Remove a warning by its ID.
|
|
481
|
+
* Requires the `members.moderate` scope.
|
|
482
|
+
*
|
|
483
|
+
* @example
|
|
484
|
+
* await client.members.removeWarning('warning-id')
|
|
485
|
+
*/
|
|
486
|
+
removeWarning(warningId) {
|
|
487
|
+
return this.http.delete(`/warnings/${warningId}`);
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Get a member's XP and level.
|
|
491
|
+
* Requires the `members.read` scope.
|
|
492
|
+
*
|
|
493
|
+
* @example
|
|
494
|
+
* const xpData = await client.members.getXP('server-id', 'user-id')
|
|
495
|
+
* console.log(`Level ${xpData.level} — ${xpData.xp} XP`)
|
|
496
|
+
*/
|
|
497
|
+
getXP(serverId, userId) {
|
|
498
|
+
return this.http.get(`/servers/${serverId}/members/${userId}/xp`);
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Set or add XP to a member.
|
|
502
|
+
* Requires the `members.manage` scope.
|
|
503
|
+
*
|
|
504
|
+
* @example
|
|
505
|
+
* // Add 50 XP
|
|
506
|
+
* await client.members.setXP('server-id', 'user-id', { add: 50 })
|
|
507
|
+
* // Set XP to a specific value
|
|
508
|
+
* await client.members.setXP('server-id', 'user-id', { xp: 1000 })
|
|
509
|
+
*/
|
|
510
|
+
setXP(serverId, userId, options) {
|
|
511
|
+
return this.http.patch(`/servers/${serverId}/members/${userId}/xp`, options);
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Get the XP leaderboard for a server.
|
|
515
|
+
* Requires the `members.read` scope.
|
|
516
|
+
*
|
|
517
|
+
* @example
|
|
518
|
+
* const top10 = await client.members.leaderboard('server-id', 10)
|
|
519
|
+
*/
|
|
520
|
+
leaderboard(serverId, limit = 10) {
|
|
521
|
+
return this.http.get(`/servers/${serverId}/leaderboard?limit=${limit}`);
|
|
522
|
+
}
|
|
429
523
|
};
|
|
430
524
|
|
|
431
525
|
// src/api/servers.ts
|
|
@@ -475,6 +569,34 @@ var ServersAPI = class {
|
|
|
475
569
|
listRoles(serverId) {
|
|
476
570
|
return this.http.get(`/servers/${serverId}/roles`);
|
|
477
571
|
}
|
|
572
|
+
/**
|
|
573
|
+
* Fetch all channel categories in a server.
|
|
574
|
+
*
|
|
575
|
+
* @example
|
|
576
|
+
* const categories = await client.servers.listCategories('server-id')
|
|
577
|
+
*/
|
|
578
|
+
listCategories(serverId) {
|
|
579
|
+
return this.http.get(`/servers/${serverId}/categories`);
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Get server statistics (member count, message count, etc.).
|
|
583
|
+
*
|
|
584
|
+
* @example
|
|
585
|
+
* const stats = await client.servers.getStats('server-id')
|
|
586
|
+
* console.log(`${stats.onlineCount} online / ${stats.memberCount} total`)
|
|
587
|
+
*/
|
|
588
|
+
getStats(serverId) {
|
|
589
|
+
return this.http.get(`/servers/${serverId}/stats`);
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Fetch all soundboard clips uploaded to a server.
|
|
593
|
+
*
|
|
594
|
+
* @example
|
|
595
|
+
* const clips = await client.servers.listSoundboard('server-id')
|
|
596
|
+
*/
|
|
597
|
+
listSoundboard(serverId) {
|
|
598
|
+
return this.http.get(`/servers/${serverId}/soundboard`);
|
|
599
|
+
}
|
|
478
600
|
};
|
|
479
601
|
|
|
480
602
|
// src/api/interactions.ts
|
|
@@ -752,6 +874,18 @@ var ChannelsAPI = class {
|
|
|
752
874
|
startTyping(channelId) {
|
|
753
875
|
return this.http.post(`/channels/${channelId}/typing`);
|
|
754
876
|
}
|
|
877
|
+
/**
|
|
878
|
+
* Bulk delete up to 100 messages from a channel at once.
|
|
879
|
+
* Requires the `messages.manage` scope.
|
|
880
|
+
* Soft-deletes all specified messages in a single operation.
|
|
881
|
+
*
|
|
882
|
+
* @example
|
|
883
|
+
* const result = await client.channels.bulkDelete('channel-id', ['msg1', 'msg2', 'msg3'])
|
|
884
|
+
* console.log(`Deleted ${result.deleted} messages`)
|
|
885
|
+
*/
|
|
886
|
+
bulkDelete(channelId, messageIds) {
|
|
887
|
+
return this.http.post(`/channels/${channelId}/bulk-delete`, { messageIds });
|
|
888
|
+
}
|
|
755
889
|
};
|
|
756
890
|
|
|
757
891
|
// src/api/reactions.ts
|
|
@@ -1060,6 +1194,224 @@ var AuditLogAPI = class {
|
|
|
1060
1194
|
}
|
|
1061
1195
|
};
|
|
1062
1196
|
|
|
1197
|
+
// src/api/forum.ts
|
|
1198
|
+
var ForumAPI = class {
|
|
1199
|
+
constructor(http) {
|
|
1200
|
+
this.http = http;
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
* List forum posts in a FORUM channel.
|
|
1204
|
+
*
|
|
1205
|
+
* @example
|
|
1206
|
+
* const posts = await client.forum.list('channel-id')
|
|
1207
|
+
*/
|
|
1208
|
+
async list(channelId, options = {}) {
|
|
1209
|
+
const params = new URLSearchParams();
|
|
1210
|
+
if (options.limit !== void 0) params.set("limit", String(options.limit));
|
|
1211
|
+
if (options.before) params.set("before", options.before);
|
|
1212
|
+
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
1213
|
+
return this.http.get(`/channels/${channelId}/forum-posts${qs}`);
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
* Create a forum post in a FORUM channel.
|
|
1217
|
+
*
|
|
1218
|
+
* @example
|
|
1219
|
+
* const post = await client.forum.create('channel-id', {
|
|
1220
|
+
* title: 'Ideas thread',
|
|
1221
|
+
* body: 'Post your ideas here!',
|
|
1222
|
+
* tags: ['idea', 'discussion'],
|
|
1223
|
+
* })
|
|
1224
|
+
*/
|
|
1225
|
+
async create(channelId, options) {
|
|
1226
|
+
return this.http.post(`/channels/${channelId}/forum-posts`, options);
|
|
1227
|
+
}
|
|
1228
|
+
/**
|
|
1229
|
+
* Edit a forum post.
|
|
1230
|
+
* The bot must be the author of the post.
|
|
1231
|
+
*
|
|
1232
|
+
* @example
|
|
1233
|
+
* await client.forum.edit('post-id', { closed: true })
|
|
1234
|
+
*/
|
|
1235
|
+
async edit(postId, options) {
|
|
1236
|
+
return this.http.patch(`/forum-posts/${postId}`, options);
|
|
1237
|
+
}
|
|
1238
|
+
/**
|
|
1239
|
+
* Delete a forum post.
|
|
1240
|
+
* The bot must be the author of the post.
|
|
1241
|
+
*
|
|
1242
|
+
* @example
|
|
1243
|
+
* await client.forum.delete('post-id')
|
|
1244
|
+
*/
|
|
1245
|
+
async delete(postId) {
|
|
1246
|
+
await this.http.delete(`/forum-posts/${postId}`);
|
|
1247
|
+
}
|
|
1248
|
+
};
|
|
1249
|
+
|
|
1250
|
+
// src/api/events.ts
|
|
1251
|
+
var EventsAPI = class {
|
|
1252
|
+
constructor(http) {
|
|
1253
|
+
this.http = http;
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* List server events.
|
|
1257
|
+
*
|
|
1258
|
+
* @example
|
|
1259
|
+
* const events = await client.events.list('server-id', { upcoming: true })
|
|
1260
|
+
*/
|
|
1261
|
+
async list(serverId, options = {}) {
|
|
1262
|
+
const params = new URLSearchParams();
|
|
1263
|
+
if (options.limit !== void 0) params.set("limit", String(options.limit));
|
|
1264
|
+
if (options.upcoming) params.set("upcoming", "true");
|
|
1265
|
+
const qs = params.toString() ? `?${params.toString()}` : "";
|
|
1266
|
+
return this.http.get(`/servers/${serverId}/events${qs}`);
|
|
1267
|
+
}
|
|
1268
|
+
/**
|
|
1269
|
+
* Fetch a single server event by ID.
|
|
1270
|
+
* Returns full attendee list.
|
|
1271
|
+
*
|
|
1272
|
+
* @example
|
|
1273
|
+
* const event = await client.events.fetch('event-id')
|
|
1274
|
+
*/
|
|
1275
|
+
async fetch(eventId) {
|
|
1276
|
+
return this.http.get(`/events/${eventId}`);
|
|
1277
|
+
}
|
|
1278
|
+
/**
|
|
1279
|
+
* Create a server event.
|
|
1280
|
+
*
|
|
1281
|
+
* @example
|
|
1282
|
+
* const event = await client.events.create('server-id', {
|
|
1283
|
+
* title: 'Game Night',
|
|
1284
|
+
* description: 'Friday fun!',
|
|
1285
|
+
* startAt: new Date(Date.now() + 86400_000).toISOString(),
|
|
1286
|
+
* })
|
|
1287
|
+
*/
|
|
1288
|
+
async create(serverId, options) {
|
|
1289
|
+
return this.http.post(`/servers/${serverId}/events`, options);
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
* Edit a server event.
|
|
1293
|
+
*
|
|
1294
|
+
* @example
|
|
1295
|
+
* await client.events.edit('event-id', { title: 'Game Night v2' })
|
|
1296
|
+
*/
|
|
1297
|
+
async edit(eventId, options) {
|
|
1298
|
+
return this.http.patch(`/events/${eventId}`, options);
|
|
1299
|
+
}
|
|
1300
|
+
/**
|
|
1301
|
+
* Delete a server event.
|
|
1302
|
+
*
|
|
1303
|
+
* @example
|
|
1304
|
+
* await client.events.delete('event-id')
|
|
1305
|
+
*/
|
|
1306
|
+
async delete(eventId) {
|
|
1307
|
+
await this.http.delete(`/events/${eventId}`);
|
|
1308
|
+
}
|
|
1309
|
+
};
|
|
1310
|
+
|
|
1311
|
+
// src/api/categories.ts
|
|
1312
|
+
var CategoriesAPI = class {
|
|
1313
|
+
constructor(http) {
|
|
1314
|
+
this.http = http;
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* List all channel categories in a server, ordered by position.
|
|
1318
|
+
*
|
|
1319
|
+
* @example
|
|
1320
|
+
* const cats = await client.categories.list('server-id')
|
|
1321
|
+
*/
|
|
1322
|
+
async list(serverId) {
|
|
1323
|
+
return this.http.get(`/servers/${serverId}/categories`);
|
|
1324
|
+
}
|
|
1325
|
+
/**
|
|
1326
|
+
* Create a new channel category.
|
|
1327
|
+
*
|
|
1328
|
+
* @example
|
|
1329
|
+
* const cat = await client.categories.create('server-id', { name: 'General', position: 0 })
|
|
1330
|
+
*/
|
|
1331
|
+
async create(serverId, options) {
|
|
1332
|
+
return this.http.post(`/servers/${serverId}/categories`, options);
|
|
1333
|
+
}
|
|
1334
|
+
/**
|
|
1335
|
+
* Edit an existing channel category.
|
|
1336
|
+
*
|
|
1337
|
+
* @example
|
|
1338
|
+
* await client.categories.edit('cat-id', { name: 'Renamed' })
|
|
1339
|
+
*/
|
|
1340
|
+
async edit(categoryId, options) {
|
|
1341
|
+
return this.http.patch(`/categories/${categoryId}`, options);
|
|
1342
|
+
}
|
|
1343
|
+
/**
|
|
1344
|
+
* Delete a channel category.
|
|
1345
|
+
*
|
|
1346
|
+
* @example
|
|
1347
|
+
* await client.categories.delete('cat-id')
|
|
1348
|
+
*/
|
|
1349
|
+
async delete(categoryId) {
|
|
1350
|
+
await this.http.delete(`/categories/${categoryId}`);
|
|
1351
|
+
}
|
|
1352
|
+
};
|
|
1353
|
+
|
|
1354
|
+
// src/api/automod.ts
|
|
1355
|
+
var AutoModAPI = class {
|
|
1356
|
+
constructor(http) {
|
|
1357
|
+
this.http = http;
|
|
1358
|
+
}
|
|
1359
|
+
/**
|
|
1360
|
+
* List all automod rules for a server.
|
|
1361
|
+
*
|
|
1362
|
+
* @example
|
|
1363
|
+
* const rules = await client.automod.list('server-id')
|
|
1364
|
+
*/
|
|
1365
|
+
async list(serverId) {
|
|
1366
|
+
return this.http.get(`/servers/${serverId}/automod`);
|
|
1367
|
+
}
|
|
1368
|
+
/**
|
|
1369
|
+
* Create a new automod rule.
|
|
1370
|
+
*
|
|
1371
|
+
* @example
|
|
1372
|
+
* await client.automod.create('server-id', { type: 'BLOCKED_WORD', value: 'badword' })
|
|
1373
|
+
* await client.automod.create('server-id', { type: 'BLOCKED_LINK', value: 'example.com' })
|
|
1374
|
+
*/
|
|
1375
|
+
async create(serverId, options) {
|
|
1376
|
+
return this.http.post(`/servers/${serverId}/automod`, options);
|
|
1377
|
+
}
|
|
1378
|
+
/**
|
|
1379
|
+
* Enable / disable a rule or update the blocked value.
|
|
1380
|
+
*
|
|
1381
|
+
* @example
|
|
1382
|
+
* await client.automod.edit('rule-id', { enabled: false })
|
|
1383
|
+
*/
|
|
1384
|
+
async edit(ruleId, options) {
|
|
1385
|
+
return this.http.patch(`/automod/${ruleId}`, options);
|
|
1386
|
+
}
|
|
1387
|
+
/**
|
|
1388
|
+
* Delete an automod rule.
|
|
1389
|
+
*
|
|
1390
|
+
* @example
|
|
1391
|
+
* await client.automod.delete('rule-id')
|
|
1392
|
+
*/
|
|
1393
|
+
async delete(ruleId) {
|
|
1394
|
+
await this.http.delete(`/automod/${ruleId}`);
|
|
1395
|
+
}
|
|
1396
|
+
};
|
|
1397
|
+
|
|
1398
|
+
// src/api/users.ts
|
|
1399
|
+
var UsersAPI = class {
|
|
1400
|
+
constructor(http) {
|
|
1401
|
+
this.http = http;
|
|
1402
|
+
}
|
|
1403
|
+
/**
|
|
1404
|
+
* Fetch a user's public profile by ID.
|
|
1405
|
+
*
|
|
1406
|
+
* @example
|
|
1407
|
+
* const user = await client.users.fetch('user-id')
|
|
1408
|
+
* console.log(user.displayName)
|
|
1409
|
+
*/
|
|
1410
|
+
async fetch(userId) {
|
|
1411
|
+
return this.http.get(`/users/${userId}`);
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1414
|
+
|
|
1063
1415
|
// src/structures/NovaInteraction.ts
|
|
1064
1416
|
var InteractionOptions = class {
|
|
1065
1417
|
constructor(data) {
|
|
@@ -1384,6 +1736,63 @@ var NovaMessage = class _NovaMessage {
|
|
|
1384
1736
|
const raw = await this._messages.fetchOne(this.id);
|
|
1385
1737
|
return new _NovaMessage(raw, this._messages, this._reactions);
|
|
1386
1738
|
}
|
|
1739
|
+
/**
|
|
1740
|
+
* Forward this message's content (and embed if present) to another channel.
|
|
1741
|
+
* Creates a new message in the target channel.
|
|
1742
|
+
*
|
|
1743
|
+
* @example
|
|
1744
|
+
* const forwarded = await msg.forward('target-channel-id')
|
|
1745
|
+
* console.log('Forwarded to:', forwarded.channelId)
|
|
1746
|
+
*/
|
|
1747
|
+
async forward(channelId) {
|
|
1748
|
+
const opts = {
|
|
1749
|
+
content: this.content || void 0,
|
|
1750
|
+
...this.embed ? { embed: this.embed } : {}
|
|
1751
|
+
};
|
|
1752
|
+
const raw = await this._messages.send(channelId, opts);
|
|
1753
|
+
return new _NovaMessage(raw, this._messages, this._reactions);
|
|
1754
|
+
}
|
|
1755
|
+
/**
|
|
1756
|
+
* Fetch detailed reaction data for a specific emoji on this message.
|
|
1757
|
+
* Returns the users who reacted with that emoji.
|
|
1758
|
+
*
|
|
1759
|
+
* @example
|
|
1760
|
+
* const reactors = await msg.fetchReactionDetails('👍')
|
|
1761
|
+
* for (const r of reactors) console.log(r.username, 'reacted 👍')
|
|
1762
|
+
*/
|
|
1763
|
+
fetchReactionDetails(emoji) {
|
|
1764
|
+
return this._reactions.fetchEmoji(this.id, emoji);
|
|
1765
|
+
}
|
|
1766
|
+
/**
|
|
1767
|
+
* Remove **all** reactions from this message.
|
|
1768
|
+
* Requires the `messages.manage` scope.
|
|
1769
|
+
*
|
|
1770
|
+
* @example
|
|
1771
|
+
* await msg.clearAllReactions()
|
|
1772
|
+
*/
|
|
1773
|
+
clearAllReactions() {
|
|
1774
|
+
return this._reactions.removeAll(this.id);
|
|
1775
|
+
}
|
|
1776
|
+
/**
|
|
1777
|
+
* Remove all reactions for a specific emoji from this message.
|
|
1778
|
+
* Requires the `messages.manage` scope.
|
|
1779
|
+
*
|
|
1780
|
+
* @example
|
|
1781
|
+
* await msg.clearReactionsFor('👍')
|
|
1782
|
+
*/
|
|
1783
|
+
clearReactionsFor(emoji) {
|
|
1784
|
+
return this._reactions.removeEmoji(this.id, emoji);
|
|
1785
|
+
}
|
|
1786
|
+
/**
|
|
1787
|
+
* Fetch a breakdown of all reactions on this message, grouped by emoji.
|
|
1788
|
+
*
|
|
1789
|
+
* @example
|
|
1790
|
+
* const details = await msg.fetchAllReactions()
|
|
1791
|
+
* for (const d of details) console.log(`${d.emoji} — ${d.count}`)
|
|
1792
|
+
*/
|
|
1793
|
+
fetchAllReactions() {
|
|
1794
|
+
return this._reactions.fetch(this.id);
|
|
1795
|
+
}
|
|
1387
1796
|
/**
|
|
1388
1797
|
* Get a URL to this message (deep link).
|
|
1389
1798
|
*/
|
|
@@ -1415,7 +1824,7 @@ var NovaMessage = class _NovaMessage {
|
|
|
1415
1824
|
|
|
1416
1825
|
// src/structures/NovaChannel.ts
|
|
1417
1826
|
var NovaChannel = class _NovaChannel {
|
|
1418
|
-
constructor(raw, channels, messages) {
|
|
1827
|
+
constructor(raw, channels, messages, webhooks, forum) {
|
|
1419
1828
|
this.id = raw.id;
|
|
1420
1829
|
this.name = raw.name;
|
|
1421
1830
|
this.type = raw.type;
|
|
@@ -1426,6 +1835,8 @@ var NovaChannel = class _NovaChannel {
|
|
|
1426
1835
|
this.createdAt = new Date(raw.createdAt);
|
|
1427
1836
|
this._channels = channels;
|
|
1428
1837
|
this._messages = messages;
|
|
1838
|
+
this._webhooks = webhooks;
|
|
1839
|
+
this._forum = forum;
|
|
1429
1840
|
}
|
|
1430
1841
|
// ─── Type guards ────────────────────────────────────────────────────────────
|
|
1431
1842
|
/** `true` for text channels. */
|
|
@@ -1502,7 +1913,7 @@ var NovaChannel = class _NovaChannel {
|
|
|
1502
1913
|
*/
|
|
1503
1914
|
async edit(options) {
|
|
1504
1915
|
const raw = await this._channels.edit(this.id, options);
|
|
1505
|
-
return new _NovaChannel(raw, this._channels, this._messages);
|
|
1916
|
+
return new _NovaChannel(raw, this._channels, this._messages, this._webhooks, this._forum);
|
|
1506
1917
|
}
|
|
1507
1918
|
/**
|
|
1508
1919
|
* Delete this channel.
|
|
@@ -1514,6 +1925,67 @@ var NovaChannel = class _NovaChannel {
|
|
|
1514
1925
|
delete() {
|
|
1515
1926
|
return this._channels.delete(this.id);
|
|
1516
1927
|
}
|
|
1928
|
+
/**
|
|
1929
|
+
* Bulk-delete multiple messages in this channel (max 100 at once).
|
|
1930
|
+
* Requires the `messages.manage` scope.
|
|
1931
|
+
*
|
|
1932
|
+
* @example
|
|
1933
|
+
* const ids = messages.map(m => m.id)
|
|
1934
|
+
* const result = await channel.bulkDelete(ids)
|
|
1935
|
+
* console.log(`Deleted ${result.deleted} messages`)
|
|
1936
|
+
*/
|
|
1937
|
+
bulkDelete(messageIds) {
|
|
1938
|
+
return this._channels.bulkDelete(this.id, messageIds);
|
|
1939
|
+
}
|
|
1940
|
+
// ─── Webhooks ────────────────────────────────────────────────────────────────
|
|
1941
|
+
/**
|
|
1942
|
+
* Create a webhook in this channel.
|
|
1943
|
+
* Requires the `webhooks.manage` scope.
|
|
1944
|
+
*
|
|
1945
|
+
* @example
|
|
1946
|
+
* const wh = await channel.createWebhook({ name: 'Notifications' })
|
|
1947
|
+
* console.log('Token:', wh.token)
|
|
1948
|
+
*/
|
|
1949
|
+
createWebhook(options) {
|
|
1950
|
+
if (!this._webhooks) throw new Error("[NovaChannel] WebhooksAPI not available \u2014 ensure you obtained this channel from client.fetchChannel()");
|
|
1951
|
+
return this._webhooks.create(this.id, options);
|
|
1952
|
+
}
|
|
1953
|
+
/**
|
|
1954
|
+
* Fetch all webhooks in this channel.
|
|
1955
|
+
* Requires the `webhooks.manage` scope.
|
|
1956
|
+
*
|
|
1957
|
+
* @example
|
|
1958
|
+
* const webhooks = await channel.fetchWebhooks()
|
|
1959
|
+
*/
|
|
1960
|
+
fetchWebhooks() {
|
|
1961
|
+
if (!this._webhooks) throw new Error("[NovaChannel] WebhooksAPI not available \u2014 ensure you obtained this channel from client.fetchChannel()");
|
|
1962
|
+
return this._webhooks.list(this.id);
|
|
1963
|
+
}
|
|
1964
|
+
// ─── Forum ───────────────────────────────────────────────────────────────────
|
|
1965
|
+
/**
|
|
1966
|
+
* Create a new post in this FORUM channel.
|
|
1967
|
+
* Requires the `channels.write` scope.
|
|
1968
|
+
*
|
|
1969
|
+
* @example
|
|
1970
|
+
* const post = await channel.createForumPost({
|
|
1971
|
+
* title: 'Announcement',
|
|
1972
|
+
* content: 'Welcome everyone!',
|
|
1973
|
+
* })
|
|
1974
|
+
*/
|
|
1975
|
+
createForumPost(options) {
|
|
1976
|
+
if (!this._forum) throw new Error("[NovaChannel] ForumAPI not available \u2014 ensure you obtained this channel from client.fetchChannel()");
|
|
1977
|
+
return this._forum.create(this.id, options);
|
|
1978
|
+
}
|
|
1979
|
+
/**
|
|
1980
|
+
* Fetch posts from this FORUM channel.
|
|
1981
|
+
*
|
|
1982
|
+
* @example
|
|
1983
|
+
* const posts = await channel.fetchForumPosts({ limit: 20 })
|
|
1984
|
+
*/
|
|
1985
|
+
fetchForumPosts(options) {
|
|
1986
|
+
if (!this._forum) throw new Error("[NovaChannel] ForumAPI not available \u2014 ensure you obtained this channel from client.fetchChannel()");
|
|
1987
|
+
return this._forum.list(this.id, options);
|
|
1988
|
+
}
|
|
1517
1989
|
// ─── Serialisation ──────────────────────────────────────────────────────────
|
|
1518
1990
|
/**
|
|
1519
1991
|
* Returns the channel as a mention-style string: `#name`.
|
|
@@ -1631,29 +2103,106 @@ var NovaMember = class {
|
|
|
1631
2103
|
removeRole(roleId) {
|
|
1632
2104
|
return this._members.removeRole(this.serverId, this.userId, roleId);
|
|
1633
2105
|
}
|
|
1634
|
-
// ───
|
|
2106
|
+
// ─── Moderation ─────────────────────────────────────────────────────────────
|
|
1635
2107
|
/**
|
|
1636
|
-
*
|
|
2108
|
+
* Issue a warning to this member.
|
|
2109
|
+
* Requires the `members.moderate` scope.
|
|
2110
|
+
*
|
|
2111
|
+
* @example
|
|
2112
|
+
* await member.warn('Excessive spamming')
|
|
1637
2113
|
*/
|
|
1638
|
-
|
|
1639
|
-
return
|
|
2114
|
+
warn(reason) {
|
|
2115
|
+
return this._members.warn(this.serverId, this.userId, reason);
|
|
1640
2116
|
}
|
|
1641
|
-
/**
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
2117
|
+
/**
|
|
2118
|
+
* Fetch all warnings for this member in this server.
|
|
2119
|
+
* Requires the `members.moderate` scope.
|
|
2120
|
+
*
|
|
2121
|
+
* @example
|
|
2122
|
+
* const warnings = await member.fetchWarnings()
|
|
2123
|
+
* console.log(`${warnings.length} warnings on record`)
|
|
2124
|
+
*/
|
|
2125
|
+
fetchWarnings() {
|
|
2126
|
+
return this._members.fetchWarnings(this.serverId, { userId: this.userId });
|
|
2127
|
+
}
|
|
2128
|
+
// ─── XP & Levels ────────────────────────────────────────────────────────────
|
|
2129
|
+
/**
|
|
2130
|
+
* Get this member's current XP and level.
|
|
2131
|
+
* Requires the `members.read` scope.
|
|
2132
|
+
*
|
|
2133
|
+
* @example
|
|
2134
|
+
* const xp = await member.getXP()
|
|
2135
|
+
* console.log(`Level ${xp.level} — ${xp.xp} XP`)
|
|
2136
|
+
*/
|
|
2137
|
+
getXP() {
|
|
2138
|
+
return this._members.getXP(this.serverId, this.userId);
|
|
2139
|
+
}
|
|
2140
|
+
/**
|
|
2141
|
+
* Set this member's XP to a specific value.
|
|
2142
|
+
* Requires the `members.manage` scope.
|
|
2143
|
+
*
|
|
2144
|
+
* @example
|
|
2145
|
+
* await member.setXP(500)
|
|
2146
|
+
*/
|
|
2147
|
+
setXP(xp) {
|
|
2148
|
+
return this._members.setXP(this.serverId, this.userId, { xp });
|
|
2149
|
+
}
|
|
2150
|
+
/**
|
|
2151
|
+
* Add (or subtract) XP to this member's current total.
|
|
2152
|
+
* Requires the `members.manage` scope.
|
|
2153
|
+
*
|
|
2154
|
+
* @example
|
|
2155
|
+
* await member.addXP(100) // reward 100 XP
|
|
2156
|
+
* await member.addXP(-50) // deduct 50 XP
|
|
2157
|
+
*/
|
|
2158
|
+
addXP(amount) {
|
|
2159
|
+
return this._members.setXP(this.serverId, this.userId, { add: amount });
|
|
2160
|
+
}
|
|
2161
|
+
/**
|
|
2162
|
+
* Delete all warnings on record for this member in this server.
|
|
2163
|
+
* Requires the `members.moderate` scope.
|
|
2164
|
+
*
|
|
2165
|
+
* @example
|
|
2166
|
+
* await member.clearWarnings()
|
|
2167
|
+
*/
|
|
2168
|
+
async clearWarnings() {
|
|
2169
|
+
const warnings = await this.fetchWarnings();
|
|
2170
|
+
await Promise.all(warnings.map((w) => this._members.removeWarning(w.id)));
|
|
2171
|
+
return warnings.length;
|
|
2172
|
+
}
|
|
2173
|
+
/**
|
|
2174
|
+
* Reset this member's XP back to zero.
|
|
2175
|
+
* Requires the `members.manage` scope.
|
|
2176
|
+
*
|
|
2177
|
+
* @example
|
|
2178
|
+
* await member.resetXP()
|
|
2179
|
+
*/
|
|
2180
|
+
resetXP() {
|
|
2181
|
+
return this._members.setXP(this.serverId, this.userId, { xp: 0 });
|
|
2182
|
+
}
|
|
2183
|
+
// ─── Serialisation ──────────────────────────────────────────────────────────
|
|
2184
|
+
/**
|
|
2185
|
+
* Returns a mention-style string: `@displayName`.
|
|
2186
|
+
*/
|
|
2187
|
+
toString() {
|
|
2188
|
+
return `@${this.displayName}`;
|
|
2189
|
+
}
|
|
2190
|
+
/** Returns the raw member data. */
|
|
2191
|
+
toJSON() {
|
|
2192
|
+
return {
|
|
2193
|
+
role: this.role,
|
|
2194
|
+
joinedAt: this.joinedAt.toISOString(),
|
|
2195
|
+
user: {
|
|
2196
|
+
id: this.userId,
|
|
2197
|
+
username: this.username,
|
|
2198
|
+
displayName: this.displayName,
|
|
2199
|
+
avatar: this.avatar,
|
|
2200
|
+
status: this.status,
|
|
2201
|
+
isBot: this.isBot
|
|
2202
|
+
}
|
|
2203
|
+
};
|
|
2204
|
+
}
|
|
2205
|
+
};
|
|
1657
2206
|
|
|
1658
2207
|
// src/structures/NovaRole.ts
|
|
1659
2208
|
var NovaRole = class {
|
|
@@ -1730,7 +2279,7 @@ var NovaRole = class {
|
|
|
1730
2279
|
|
|
1731
2280
|
// src/structures/NovaServer.ts
|
|
1732
2281
|
var NovaServerWrapper = class {
|
|
1733
|
-
constructor(raw, servers, channels, members, invites, roles, messages) {
|
|
2282
|
+
constructor(raw, servers, channels, members, invites, roles, messages, categories, events, automod, auditLog) {
|
|
1734
2283
|
this.id = raw.id;
|
|
1735
2284
|
this.name = raw.name;
|
|
1736
2285
|
this.icon = raw.icon;
|
|
@@ -1744,6 +2293,10 @@ var NovaServerWrapper = class {
|
|
|
1744
2293
|
this._invites = invites;
|
|
1745
2294
|
this._roles = roles;
|
|
1746
2295
|
this._messages = messages;
|
|
2296
|
+
this._categories = categories;
|
|
2297
|
+
this._events = events;
|
|
2298
|
+
this._automod = automod;
|
|
2299
|
+
this._auditLog = auditLog;
|
|
1747
2300
|
}
|
|
1748
2301
|
// ─── Server management ────────────────────────────────────────────────────
|
|
1749
2302
|
/**
|
|
@@ -1822,14 +2375,25 @@ var NovaServerWrapper = class {
|
|
|
1822
2375
|
}
|
|
1823
2376
|
// ─── Roles ────────────────────────────────────────────────────────────────
|
|
1824
2377
|
/**
|
|
1825
|
-
*
|
|
2378
|
+
* List all custom roles in this server, sorted by position.
|
|
1826
2379
|
*
|
|
1827
2380
|
* @example
|
|
1828
2381
|
* const roles = await server.fetchRoles()
|
|
2382
|
+
* const admins = roles.filter(r => r.name === 'Admin')
|
|
1829
2383
|
*/
|
|
1830
2384
|
fetchRoles() {
|
|
1831
2385
|
return this._roles.list(this.id);
|
|
1832
2386
|
}
|
|
2387
|
+
/**
|
|
2388
|
+
* Create a new custom role in this server.
|
|
2389
|
+
* Requires the `roles.manage` scope.
|
|
2390
|
+
*
|
|
2391
|
+
* @example
|
|
2392
|
+
* const role = await server.createRole({ name: 'Supporter', color: '#00d4ff', hoist: true })
|
|
2393
|
+
*/
|
|
2394
|
+
createRole(options) {
|
|
2395
|
+
return this._roles.create(this.id, options);
|
|
2396
|
+
}
|
|
1833
2397
|
// ─── Invites ──────────────────────────────────────────────────────────────
|
|
1834
2398
|
/**
|
|
1835
2399
|
* Fetch all active invites for this server.
|
|
@@ -1860,6 +2424,133 @@ var NovaServerWrapper = class {
|
|
|
1860
2424
|
send(channelId, content) {
|
|
1861
2425
|
return this._messages.send(channelId, { content });
|
|
1862
2426
|
}
|
|
2427
|
+
// ─── Categories ───────────────────────────────────────────────────────────
|
|
2428
|
+
/**
|
|
2429
|
+
* Fetch all channel categories in this server.
|
|
2430
|
+
*
|
|
2431
|
+
* @example
|
|
2432
|
+
* const cats = await server.fetchCategories()
|
|
2433
|
+
* const general = cats.find(c => c.name === 'General')
|
|
2434
|
+
*/
|
|
2435
|
+
fetchCategories() {
|
|
2436
|
+
if (!this._categories) throw new Error("[NovaServerWrapper] CategoriesAPI not available");
|
|
2437
|
+
return this._categories.list(this.id);
|
|
2438
|
+
}
|
|
2439
|
+
/**
|
|
2440
|
+
* Create a new channel category in this server.
|
|
2441
|
+
* Requires the `channels.manage` scope.
|
|
2442
|
+
*
|
|
2443
|
+
* @example
|
|
2444
|
+
* const cat = await server.createCategory({ name: 'Bot Channels' })
|
|
2445
|
+
*/
|
|
2446
|
+
createCategory(options) {
|
|
2447
|
+
if (!this._categories) throw new Error("[NovaServerWrapper] CategoriesAPI not available");
|
|
2448
|
+
return this._categories.create(this.id, options);
|
|
2449
|
+
}
|
|
2450
|
+
// ─── Events ───────────────────────────────────────────────────────────────
|
|
2451
|
+
/**
|
|
2452
|
+
* Fetch server events. Pass `{ upcoming: true }` to only return future events.
|
|
2453
|
+
*
|
|
2454
|
+
* @example
|
|
2455
|
+
* const events = await server.fetchEvents({ upcoming: true })
|
|
2456
|
+
*/
|
|
2457
|
+
fetchEvents(options = {}) {
|
|
2458
|
+
if (!this._events) throw new Error("[NovaServerWrapper] EventsAPI not available");
|
|
2459
|
+
return this._events.list(this.id, options);
|
|
2460
|
+
}
|
|
2461
|
+
/**
|
|
2462
|
+
* Create a new server event.
|
|
2463
|
+
* Requires the `server.manage` scope.
|
|
2464
|
+
*
|
|
2465
|
+
* @example
|
|
2466
|
+
* const event = await server.createEvent({
|
|
2467
|
+
* title: 'Game Night',
|
|
2468
|
+
* startAt: new Date('2025-09-01T20:00:00Z').toISOString(),
|
|
2469
|
+
* })
|
|
2470
|
+
*/
|
|
2471
|
+
createEvent(options) {
|
|
2472
|
+
if (!this._events) throw new Error("[NovaServerWrapper] EventsAPI not available");
|
|
2473
|
+
return this._events.create(this.id, options);
|
|
2474
|
+
}
|
|
2475
|
+
// ─── Stats & Audit Log ────────────────────────────────────────────────────
|
|
2476
|
+
/**
|
|
2477
|
+
* Fetch server statistics (member count, message count, etc.).
|
|
2478
|
+
*
|
|
2479
|
+
* @example
|
|
2480
|
+
* const stats = await server.fetchStats()
|
|
2481
|
+
* console.log(`Online: ${stats.onlineCount} / ${stats.memberCount}`)
|
|
2482
|
+
*/
|
|
2483
|
+
fetchStats() {
|
|
2484
|
+
return this._servers.getStats(this.id);
|
|
2485
|
+
}
|
|
2486
|
+
/**
|
|
2487
|
+
* Fetch the audit log for this server.
|
|
2488
|
+
* Requires the `audit-log.read` scope.
|
|
2489
|
+
*
|
|
2490
|
+
* @example
|
|
2491
|
+
* const log = await server.fetchAuditLog({ action: 'member.banned', limit: 20 })
|
|
2492
|
+
*/
|
|
2493
|
+
fetchAuditLog(options = {}) {
|
|
2494
|
+
if (!this._auditLog) throw new Error("[NovaServerWrapper] AuditLogAPI not available");
|
|
2495
|
+
return this._auditLog.fetch(this.id, options);
|
|
2496
|
+
}
|
|
2497
|
+
// ─── Warnings & Leaderboard ───────────────────────────────────────────────
|
|
2498
|
+
/**
|
|
2499
|
+
* Issue a warning to a member in this server.
|
|
2500
|
+
* Requires the `members.moderate` scope.
|
|
2501
|
+
*
|
|
2502
|
+
* @example
|
|
2503
|
+
* await server.warn('user-id', 'Insulting other members')
|
|
2504
|
+
*/
|
|
2505
|
+
warn(userId, reason) {
|
|
2506
|
+
return this._members.warn(this.id, userId, reason);
|
|
2507
|
+
}
|
|
2508
|
+
/**
|
|
2509
|
+
* Fetch warnings for this server, optionally filtered by user.
|
|
2510
|
+
* Requires the `members.moderate` scope.
|
|
2511
|
+
*
|
|
2512
|
+
* @example
|
|
2513
|
+
* const all = await server.fetchWarnings()
|
|
2514
|
+
* const userWarns = await server.fetchWarnings({ userId: 'user-id' })
|
|
2515
|
+
*/
|
|
2516
|
+
fetchWarnings(options = {}) {
|
|
2517
|
+
return this._members.fetchWarnings(this.id, options);
|
|
2518
|
+
}
|
|
2519
|
+
/**
|
|
2520
|
+
* Fetch the XP leaderboard for this server.
|
|
2521
|
+
* Requires the `members.read` scope.
|
|
2522
|
+
*
|
|
2523
|
+
* @example
|
|
2524
|
+
* const top = await server.fetchLeaderboard(10)
|
|
2525
|
+
* top.forEach(e => console.log(`#${e.rank} ${e.user.displayName} — ${e.xp} XP`))
|
|
2526
|
+
*/
|
|
2527
|
+
fetchLeaderboard(limit = 10) {
|
|
2528
|
+
return this._members.leaderboard(this.id, limit);
|
|
2529
|
+
}
|
|
2530
|
+
// ─── AutoMod ─────────────────────────────────────────────────────────────
|
|
2531
|
+
/**
|
|
2532
|
+
* Fetch all AutoMod rules for this server.
|
|
2533
|
+
* Requires the `server.manage` scope.
|
|
2534
|
+
*
|
|
2535
|
+
* @example
|
|
2536
|
+
* const rules = await server.fetchAutoModRules()
|
|
2537
|
+
* const active = rules.filter(r => r.enabled)
|
|
2538
|
+
*/
|
|
2539
|
+
fetchAutoModRules() {
|
|
2540
|
+
if (!this._automod) throw new Error("[NovaServerWrapper] AutoModAPI not available");
|
|
2541
|
+
return this._automod.list(this.id);
|
|
2542
|
+
}
|
|
2543
|
+
/**
|
|
2544
|
+
* Create a new AutoMod rule for this server.
|
|
2545
|
+
* Requires the `server.manage` scope.
|
|
2546
|
+
*
|
|
2547
|
+
* @example
|
|
2548
|
+
* await server.createAutoModRule({ type: 'BLOCKED_WORD', value: 'badword' })
|
|
2549
|
+
*/
|
|
2550
|
+
createAutoModRule(options) {
|
|
2551
|
+
if (!this._automod) throw new Error("[NovaServerWrapper] AutoModAPI not available");
|
|
2552
|
+
return this._automod.create(this.id, options);
|
|
2553
|
+
}
|
|
1863
2554
|
// ─── Helpers ─────────────────────────────────────────────────────────────
|
|
1864
2555
|
toJSON() {
|
|
1865
2556
|
return {
|
|
@@ -1987,6 +2678,265 @@ var NovaWebhook = class {
|
|
|
1987
2678
|
}
|
|
1988
2679
|
};
|
|
1989
2680
|
|
|
2681
|
+
// src/structures/NovaForumPost.ts
|
|
2682
|
+
var NovaForumPost = class _NovaForumPost {
|
|
2683
|
+
constructor(raw, forum) {
|
|
2684
|
+
this.raw = raw;
|
|
2685
|
+
this.forum = forum;
|
|
2686
|
+
this.id = raw.id;
|
|
2687
|
+
this.channelId = raw.channelId;
|
|
2688
|
+
this.authorId = raw.authorId;
|
|
2689
|
+
this.title = raw.title;
|
|
2690
|
+
this.body = raw.body;
|
|
2691
|
+
this.tags = raw.tags;
|
|
2692
|
+
this.pinned = raw.pinned;
|
|
2693
|
+
this.closed = raw.closed;
|
|
2694
|
+
this.upvoteCount = raw.upvoteCount;
|
|
2695
|
+
this.replyCount = raw.replyCount;
|
|
2696
|
+
this.author = raw.author;
|
|
2697
|
+
this.createdAt = raw.createdAt;
|
|
2698
|
+
this.updatedAt = raw.updatedAt;
|
|
2699
|
+
}
|
|
2700
|
+
/**
|
|
2701
|
+
* Edit this forum post.
|
|
2702
|
+
*
|
|
2703
|
+
* @example
|
|
2704
|
+
* await post.edit({ title: 'Updated title' })
|
|
2705
|
+
*/
|
|
2706
|
+
async edit(options) {
|
|
2707
|
+
const updated = await this.forum.edit(this.id, options);
|
|
2708
|
+
return new _NovaForumPost(updated, this.forum);
|
|
2709
|
+
}
|
|
2710
|
+
/**
|
|
2711
|
+
* Close the forum post (no new replies).
|
|
2712
|
+
*
|
|
2713
|
+
* @example
|
|
2714
|
+
* await post.close()
|
|
2715
|
+
*/
|
|
2716
|
+
async close() {
|
|
2717
|
+
return this.edit({ closed: true });
|
|
2718
|
+
}
|
|
2719
|
+
/**
|
|
2720
|
+
* Re-open a closed forum post.
|
|
2721
|
+
*
|
|
2722
|
+
* @example
|
|
2723
|
+
* await post.open()
|
|
2724
|
+
*/
|
|
2725
|
+
async open() {
|
|
2726
|
+
return this.edit({ closed: false });
|
|
2727
|
+
}
|
|
2728
|
+
/**
|
|
2729
|
+
* Pin this forum post in the channel.
|
|
2730
|
+
*
|
|
2731
|
+
* @example
|
|
2732
|
+
* await post.pin()
|
|
2733
|
+
*/
|
|
2734
|
+
async pin() {
|
|
2735
|
+
return this.edit({ pinned: true });
|
|
2736
|
+
}
|
|
2737
|
+
/**
|
|
2738
|
+
* Unpin this forum post.
|
|
2739
|
+
*
|
|
2740
|
+
* @example
|
|
2741
|
+
* await post.unpin()
|
|
2742
|
+
*/
|
|
2743
|
+
async unpin() {
|
|
2744
|
+
return this.edit({ pinned: false });
|
|
2745
|
+
}
|
|
2746
|
+
/**
|
|
2747
|
+
* Delete this forum post.
|
|
2748
|
+
*
|
|
2749
|
+
* @example
|
|
2750
|
+
* await post.delete()
|
|
2751
|
+
*/
|
|
2752
|
+
async delete() {
|
|
2753
|
+
await this.forum.delete(this.id);
|
|
2754
|
+
}
|
|
2755
|
+
/** Whether this post was created by the currently connected bot. */
|
|
2756
|
+
get isOwnPost() {
|
|
2757
|
+
return this.authorId === this.author.id;
|
|
2758
|
+
}
|
|
2759
|
+
/** Returns `true` if the post has been closed. */
|
|
2760
|
+
get isClosed() {
|
|
2761
|
+
return this.closed;
|
|
2762
|
+
}
|
|
2763
|
+
/** Returns `true` if the post is pinned. */
|
|
2764
|
+
get isPinned() {
|
|
2765
|
+
return this.pinned;
|
|
2766
|
+
}
|
|
2767
|
+
toJSON() {
|
|
2768
|
+
return { ...this.raw };
|
|
2769
|
+
}
|
|
2770
|
+
};
|
|
2771
|
+
|
|
2772
|
+
// src/structures/NovaServerEvent.ts
|
|
2773
|
+
var NovaServerEvent = class _NovaServerEvent {
|
|
2774
|
+
constructor(raw, events) {
|
|
2775
|
+
this.raw = raw;
|
|
2776
|
+
this.events = events;
|
|
2777
|
+
this.id = raw.id;
|
|
2778
|
+
this.serverId = raw.serverId;
|
|
2779
|
+
this.channelId = raw.channelId;
|
|
2780
|
+
this.createdById = raw.createdById;
|
|
2781
|
+
this.title = raw.title;
|
|
2782
|
+
this.description = raw.description;
|
|
2783
|
+
this.imageUrl = raw.imageUrl;
|
|
2784
|
+
this.location = raw.location;
|
|
2785
|
+
this.startAt = raw.startAt;
|
|
2786
|
+
this.endAt = raw.endAt;
|
|
2787
|
+
this.attendeeCount = raw.attendeeCount;
|
|
2788
|
+
this.createdAt = raw.createdAt;
|
|
2789
|
+
}
|
|
2790
|
+
/**
|
|
2791
|
+
* Edit this event.
|
|
2792
|
+
*
|
|
2793
|
+
* @example
|
|
2794
|
+
* await event.edit({ title: 'New Title' })
|
|
2795
|
+
*/
|
|
2796
|
+
async edit(options) {
|
|
2797
|
+
const updated = await this.events.edit(this.id, options);
|
|
2798
|
+
return new _NovaServerEvent(updated, this.events);
|
|
2799
|
+
}
|
|
2800
|
+
/**
|
|
2801
|
+
* Fetch full event details including the attendee list.
|
|
2802
|
+
*
|
|
2803
|
+
* @example
|
|
2804
|
+
* const full = await event.fetchAttendees()
|
|
2805
|
+
* console.log(`${full.attendees.length} attendees`)
|
|
2806
|
+
*/
|
|
2807
|
+
async fetchAttendees() {
|
|
2808
|
+
const data = await this.events.fetch(this.id);
|
|
2809
|
+
return {
|
|
2810
|
+
event: new _NovaServerEvent(data, this.events),
|
|
2811
|
+
attendees: data.attendees
|
|
2812
|
+
};
|
|
2813
|
+
}
|
|
2814
|
+
/**
|
|
2815
|
+
* Delete this event.
|
|
2816
|
+
*
|
|
2817
|
+
* @example
|
|
2818
|
+
* await event.delete()
|
|
2819
|
+
*/
|
|
2820
|
+
async delete() {
|
|
2821
|
+
await this.events.delete(this.id);
|
|
2822
|
+
}
|
|
2823
|
+
/**
|
|
2824
|
+
* Whether the event has already started.
|
|
2825
|
+
*/
|
|
2826
|
+
get hasStarted() {
|
|
2827
|
+
return new Date(this.startAt) <= /* @__PURE__ */ new Date();
|
|
2828
|
+
}
|
|
2829
|
+
/**
|
|
2830
|
+
* Whether the event has ended.
|
|
2831
|
+
* Returns `false` if no `endAt` is set.
|
|
2832
|
+
*/
|
|
2833
|
+
get hasEnded() {
|
|
2834
|
+
return this.endAt ? new Date(this.endAt) <= /* @__PURE__ */ new Date() : false;
|
|
2835
|
+
}
|
|
2836
|
+
/**
|
|
2837
|
+
* Whether this is an upcoming event that has not yet started.
|
|
2838
|
+
*/
|
|
2839
|
+
get isUpcoming() {
|
|
2840
|
+
return new Date(this.startAt) > /* @__PURE__ */ new Date();
|
|
2841
|
+
}
|
|
2842
|
+
toJSON() {
|
|
2843
|
+
return { ...this.raw };
|
|
2844
|
+
}
|
|
2845
|
+
};
|
|
2846
|
+
|
|
2847
|
+
// src/structures/NovaBan.ts
|
|
2848
|
+
var NovaBan = class {
|
|
2849
|
+
constructor(raw, serverId, members) {
|
|
2850
|
+
this.userId = raw.userId;
|
|
2851
|
+
this.username = raw.username;
|
|
2852
|
+
this.displayName = raw.displayName;
|
|
2853
|
+
this.avatar = raw.avatar;
|
|
2854
|
+
this.reason = raw.reason;
|
|
2855
|
+
this.bannedAt = raw.bannedAt;
|
|
2856
|
+
this.moderatorId = raw.moderatorId;
|
|
2857
|
+
this.serverId = serverId;
|
|
2858
|
+
this._members = members;
|
|
2859
|
+
}
|
|
2860
|
+
/**
|
|
2861
|
+
* Revoke this ban, allowing the user to rejoin the server.
|
|
2862
|
+
* Requires the `members.ban` scope.
|
|
2863
|
+
*
|
|
2864
|
+
* @example
|
|
2865
|
+
* await ban.unban()
|
|
2866
|
+
*/
|
|
2867
|
+
unban() {
|
|
2868
|
+
return this._members.unban(this.serverId, this.userId);
|
|
2869
|
+
}
|
|
2870
|
+
/**
|
|
2871
|
+
* When the ban was issued as a `Date` object.
|
|
2872
|
+
*/
|
|
2873
|
+
get bannedAtDate() {
|
|
2874
|
+
return new Date(this.bannedAt);
|
|
2875
|
+
}
|
|
2876
|
+
/**
|
|
2877
|
+
* Human-readable label: `"displayName (username)"`.
|
|
2878
|
+
*/
|
|
2879
|
+
get label() {
|
|
2880
|
+
return `${this.displayName} (${this.username})`;
|
|
2881
|
+
}
|
|
2882
|
+
toJSON() {
|
|
2883
|
+
return {
|
|
2884
|
+
userId: this.userId,
|
|
2885
|
+
username: this.username,
|
|
2886
|
+
displayName: this.displayName,
|
|
2887
|
+
avatar: this.avatar,
|
|
2888
|
+
reason: this.reason,
|
|
2889
|
+
bannedAt: this.bannedAt,
|
|
2890
|
+
moderatorId: this.moderatorId
|
|
2891
|
+
};
|
|
2892
|
+
}
|
|
2893
|
+
};
|
|
2894
|
+
|
|
2895
|
+
// src/structures/NovaWarning.ts
|
|
2896
|
+
var NovaWarning = class {
|
|
2897
|
+
constructor(raw, members) {
|
|
2898
|
+
this.id = raw.id;
|
|
2899
|
+
this.serverId = raw.serverId;
|
|
2900
|
+
this.userId = raw.userId;
|
|
2901
|
+
this.moderatorId = raw.moderatorId;
|
|
2902
|
+
this.reason = raw.reason;
|
|
2903
|
+
this.createdAt = raw.createdAt;
|
|
2904
|
+
this._members = members;
|
|
2905
|
+
}
|
|
2906
|
+
/**
|
|
2907
|
+
* Delete (expunge) this warning from the record.
|
|
2908
|
+
* Requires the `members.moderate` scope.
|
|
2909
|
+
*
|
|
2910
|
+
* @example
|
|
2911
|
+
* await warning.delete()
|
|
2912
|
+
*/
|
|
2913
|
+
delete() {
|
|
2914
|
+
return this._members.removeWarning(this.id);
|
|
2915
|
+
}
|
|
2916
|
+
/**
|
|
2917
|
+
* When the warning was issued as a `Date` object.
|
|
2918
|
+
*/
|
|
2919
|
+
get issuedAt() {
|
|
2920
|
+
return new Date(this.createdAt);
|
|
2921
|
+
}
|
|
2922
|
+
/**
|
|
2923
|
+
* How long ago the warning was issued, in milliseconds.
|
|
2924
|
+
*/
|
|
2925
|
+
get ageMs() {
|
|
2926
|
+
return Date.now() - this.issuedAt.getTime();
|
|
2927
|
+
}
|
|
2928
|
+
toJSON() {
|
|
2929
|
+
return {
|
|
2930
|
+
id: this.id,
|
|
2931
|
+
serverId: this.serverId,
|
|
2932
|
+
userId: this.userId,
|
|
2933
|
+
moderatorId: this.moderatorId,
|
|
2934
|
+
reason: this.reason,
|
|
2935
|
+
createdAt: this.createdAt
|
|
2936
|
+
};
|
|
2937
|
+
}
|
|
2938
|
+
};
|
|
2939
|
+
|
|
1990
2940
|
// src/client.ts
|
|
1991
2941
|
var NovaClient = class extends import_node_events.EventEmitter {
|
|
1992
2942
|
constructor(options) {
|
|
@@ -2024,6 +2974,11 @@ var NovaClient = class extends import_node_events.EventEmitter {
|
|
|
2024
2974
|
this.invites = new InvitesAPI(this.http);
|
|
2025
2975
|
this.webhooks = new WebhooksAPI(this.http);
|
|
2026
2976
|
this.auditLog = new AuditLogAPI(this.http);
|
|
2977
|
+
this.forum = new ForumAPI(this.http);
|
|
2978
|
+
this.events = new EventsAPI(this.http);
|
|
2979
|
+
this.categories = new CategoriesAPI(this.http);
|
|
2980
|
+
this.automod = new AutoModAPI(this.http);
|
|
2981
|
+
this.users = new UsersAPI(this.http);
|
|
2027
2982
|
this.on("error", () => {
|
|
2028
2983
|
});
|
|
2029
2984
|
const cleanup = () => this.disconnect();
|
|
@@ -2235,16 +3190,53 @@ var NovaClient = class extends import_node_events.EventEmitter {
|
|
|
2235
3190
|
case "server.updated":
|
|
2236
3191
|
this.emit("serverUpdate", event.data);
|
|
2237
3192
|
break;
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
3193
|
+
case "invite.created":
|
|
3194
|
+
this.emit("inviteCreate", event.data);
|
|
3195
|
+
break;
|
|
3196
|
+
case "invite.deleted":
|
|
3197
|
+
this.emit("inviteDelete", event.data);
|
|
3198
|
+
break;
|
|
3199
|
+
case "forum.post.created": {
|
|
3200
|
+
const rawPost = event.data;
|
|
3201
|
+
this.emit("forumPostCreate", new NovaForumPost(rawPost, this.forum));
|
|
3202
|
+
break;
|
|
3203
|
+
}
|
|
3204
|
+
case "event.created": {
|
|
3205
|
+
const rawEvent = event.data;
|
|
3206
|
+
this.emit("eventCreate", new NovaServerEvent(rawEvent, this.events));
|
|
3207
|
+
break;
|
|
3208
|
+
}
|
|
3209
|
+
case "event.updated":
|
|
3210
|
+
this.emit("eventUpdate", event.data);
|
|
3211
|
+
break;
|
|
3212
|
+
case "event.deleted":
|
|
3213
|
+
this.emit("eventDelete", event.data);
|
|
3214
|
+
break;
|
|
3215
|
+
case "category.created":
|
|
3216
|
+
this.emit("categoryCreate", event.data);
|
|
3217
|
+
break;
|
|
3218
|
+
case "category.updated":
|
|
3219
|
+
this.emit("categoryUpdate", event.data);
|
|
3220
|
+
break;
|
|
3221
|
+
case "category.deleted":
|
|
3222
|
+
this.emit("categoryDelete", event.data);
|
|
3223
|
+
break;
|
|
3224
|
+
case "member.warned":
|
|
3225
|
+
this.emit("memberWarned", event.data);
|
|
3226
|
+
break;
|
|
3227
|
+
case "messages.bulk_deleted":
|
|
3228
|
+
this.emit("messagesBulkDelete", event.data);
|
|
3229
|
+
break;
|
|
3230
|
+
}
|
|
3231
|
+
});
|
|
3232
|
+
this.socket.on("bot:error", (err) => {
|
|
3233
|
+
this.emit("error", err);
|
|
3234
|
+
});
|
|
3235
|
+
this.socket.on("disconnect", (reason) => {
|
|
3236
|
+
this.emit("disconnect", reason);
|
|
3237
|
+
});
|
|
3238
|
+
});
|
|
3239
|
+
}
|
|
2248
3240
|
/**
|
|
2249
3241
|
* Register a recurring task that fires at a set interval.
|
|
2250
3242
|
* All cron tasks are automatically cancelled on `disconnect()`.
|
|
@@ -2301,7 +3293,7 @@ var NovaClient = class extends import_node_events.EventEmitter {
|
|
|
2301
3293
|
*/
|
|
2302
3294
|
async fetchChannel(channelId) {
|
|
2303
3295
|
const raw = await this.channels.fetch(channelId);
|
|
2304
|
-
return new NovaChannel(raw, this.channels, this.messages);
|
|
3296
|
+
return new NovaChannel(raw, this.channels, this.messages, this.webhooks, this.forum);
|
|
2305
3297
|
}
|
|
2306
3298
|
/**
|
|
2307
3299
|
* Fetch all channels in a server and return them as `NovaChannel` wrappers.
|
|
@@ -2312,7 +3304,7 @@ var NovaClient = class extends import_node_events.EventEmitter {
|
|
|
2312
3304
|
*/
|
|
2313
3305
|
async fetchChannels(serverId) {
|
|
2314
3306
|
const list = await this.channels.list(serverId);
|
|
2315
|
-
return list.map((raw) => new NovaChannel(raw, this.channels, this.messages));
|
|
3307
|
+
return list.map((raw) => new NovaChannel(raw, this.channels, this.messages, this.webhooks, this.forum));
|
|
2316
3308
|
}
|
|
2317
3309
|
/**
|
|
2318
3310
|
* Fetch all members in a server and return them as `NovaMember` wrappers.
|
|
@@ -2337,6 +3329,36 @@ var NovaClient = class extends import_node_events.EventEmitter {
|
|
|
2337
3329
|
const raw = await this.members.fetch(serverId, userId);
|
|
2338
3330
|
return new NovaMember(raw, serverId, this.members);
|
|
2339
3331
|
}
|
|
3332
|
+
/**
|
|
3333
|
+
* Fetch all bans in a server and return them as `NovaBan` wrappers.
|
|
3334
|
+
* Each `NovaBan` has an `.unban()` convenience method.
|
|
3335
|
+
* Requires the `members.ban` scope.
|
|
3336
|
+
*
|
|
3337
|
+
* @example
|
|
3338
|
+
* const bans = await client.fetchBans('server-id')
|
|
3339
|
+
* for (const ban of bans) {
|
|
3340
|
+
* if (ban.reason === 'test') await ban.unban()
|
|
3341
|
+
* }
|
|
3342
|
+
*/
|
|
3343
|
+
async fetchBans(serverId) {
|
|
3344
|
+
const list = await this.members.listBans(serverId);
|
|
3345
|
+
return list.map((raw) => new NovaBan(raw, serverId, this.members));
|
|
3346
|
+
}
|
|
3347
|
+
/**
|
|
3348
|
+
* Fetch warnings for a member (or all members) in a server and return them
|
|
3349
|
+
* as `NovaWarning` wrappers. Each wrapper has a `.delete()` convenience method.
|
|
3350
|
+
* Requires the `members.moderate` scope.
|
|
3351
|
+
*
|
|
3352
|
+
* @example
|
|
3353
|
+
* const warnings = await client.fetchMemberWarnings('server-id', 'user-id')
|
|
3354
|
+
* for (const w of warnings) {
|
|
3355
|
+
* if (w.ageMs > 30 * 24 * 60 * 60_000) await w.delete() // older than 30 days
|
|
3356
|
+
* }
|
|
3357
|
+
*/
|
|
3358
|
+
async fetchMemberWarnings(serverId, userId) {
|
|
3359
|
+
const list = await this.members.fetchWarnings(serverId, userId ? { userId } : {});
|
|
3360
|
+
return list.map((raw) => new NovaWarning(raw, this.members));
|
|
3361
|
+
}
|
|
2340
3362
|
/**
|
|
2341
3363
|
* Fetch a single server by ID and return it as a `NovaServerWrapper`.
|
|
2342
3364
|
*
|
|
@@ -2346,7 +3368,7 @@ var NovaClient = class extends import_node_events.EventEmitter {
|
|
|
2346
3368
|
*/
|
|
2347
3369
|
async fetchServer(serverId) {
|
|
2348
3370
|
const raw = await this.servers.fetch(serverId);
|
|
2349
|
-
return new NovaServerWrapper(raw, this.servers, this.channels, this.members, this.invites, this.roles, this.messages);
|
|
3371
|
+
return new NovaServerWrapper(raw, this.servers, this.channels, this.members, this.invites, this.roles, this.messages, this.categories, this.events, this.automod, this.auditLog);
|
|
2350
3372
|
}
|
|
2351
3373
|
/**
|
|
2352
3374
|
* Fetch all servers the bot is in and return them as `NovaServerWrapper` objects.
|
|
@@ -2357,7 +3379,7 @@ var NovaClient = class extends import_node_events.EventEmitter {
|
|
|
2357
3379
|
*/
|
|
2358
3380
|
async fetchServers() {
|
|
2359
3381
|
const list = await this.servers.list();
|
|
2360
|
-
return list.map((raw) => new NovaServerWrapper(raw, this.servers, this.channels, this.members, this.invites, this.roles, this.messages));
|
|
3382
|
+
return list.map((raw) => new NovaServerWrapper(raw, this.servers, this.channels, this.members, this.invites, this.roles, this.messages, this.categories, this.events, this.automod, this.auditLog));
|
|
2361
3383
|
}
|
|
2362
3384
|
/**
|
|
2363
3385
|
* Fetch all custom roles in a server and return them as `NovaRole` wrappers.
|
|
@@ -2413,6 +3435,116 @@ var NovaClient = class extends import_node_events.EventEmitter {
|
|
|
2413
3435
|
const raw = await this.webhooks.fetch(webhookId);
|
|
2414
3436
|
return new NovaWebhook(raw, this.webhooks);
|
|
2415
3437
|
}
|
|
3438
|
+
/**
|
|
3439
|
+
* Fetch forum posts from a FORUM channel and return them as `NovaForumPost` wrappers.
|
|
3440
|
+
*
|
|
3441
|
+
* @example
|
|
3442
|
+
* const posts = await client.fetchForumPosts('channel-id', { limit: 20 })
|
|
3443
|
+
* const open = posts.filter(p => !p.isClosed)
|
|
3444
|
+
*/
|
|
3445
|
+
async fetchForumPosts(channelId, options) {
|
|
3446
|
+
const list = await this.forum.list(channelId, options);
|
|
3447
|
+
return list.map((raw) => new NovaForumPost(raw, this.forum));
|
|
3448
|
+
}
|
|
3449
|
+
/**
|
|
3450
|
+
* Fetch server events and return them as `NovaServerEvent` wrappers.
|
|
3451
|
+
*
|
|
3452
|
+
* @example
|
|
3453
|
+
* const upcoming = await client.fetchEvents('server-id', { upcoming: true })
|
|
3454
|
+
* for (const event of upcoming) console.log(event.title)
|
|
3455
|
+
*/
|
|
3456
|
+
async fetchEvents(serverId, options) {
|
|
3457
|
+
const list = await this.events.list(serverId, options);
|
|
3458
|
+
return list.map((raw) => new NovaServerEvent(raw, this.events));
|
|
3459
|
+
}
|
|
3460
|
+
/**
|
|
3461
|
+
* Fetch a single server event by ID and return it as a `NovaServerEvent` wrapper.
|
|
3462
|
+
*
|
|
3463
|
+
* @example
|
|
3464
|
+
* const event = await client.fetchEvent('event-id')
|
|
3465
|
+
* if (event.isUpcoming) await event.edit({ title: 'Updated!' })
|
|
3466
|
+
*/
|
|
3467
|
+
async fetchEvent(eventId) {
|
|
3468
|
+
const raw = await this.events.fetch(eventId);
|
|
3469
|
+
return new NovaServerEvent(raw, this.events);
|
|
3470
|
+
}
|
|
3471
|
+
/**
|
|
3472
|
+
* Fetch a user's public profile.
|
|
3473
|
+
*
|
|
3474
|
+
* @example
|
|
3475
|
+
* const user = await client.fetchUserProfile('user-id')
|
|
3476
|
+
* console.log(user.bio)
|
|
3477
|
+
*/
|
|
3478
|
+
fetchUserProfile(userId) {
|
|
3479
|
+
return this.users.fetch(userId);
|
|
3480
|
+
}
|
|
3481
|
+
/**
|
|
3482
|
+
* Fetch the XP leaderboard for a server.
|
|
3483
|
+
*
|
|
3484
|
+
* @example
|
|
3485
|
+
* const top = await client.fetchLeaderboard('server-id', 10)
|
|
3486
|
+
* top.forEach(entry => console.log(`#${entry.rank} ${entry.user.username} — ${entry.xp} XP`))
|
|
3487
|
+
*/
|
|
3488
|
+
fetchLeaderboard(serverId, limit = 10) {
|
|
3489
|
+
return this.members.leaderboard(serverId, limit);
|
|
3490
|
+
}
|
|
3491
|
+
/**
|
|
3492
|
+
* Fetch warnings in a server, optionally filtered by user.
|
|
3493
|
+
*
|
|
3494
|
+
* @example
|
|
3495
|
+
* const warnings = await client.fetchWarnings('server-id', { userId: 'user-id' })
|
|
3496
|
+
*/
|
|
3497
|
+
fetchWarnings(serverId, options) {
|
|
3498
|
+
return this.members.fetchWarnings(serverId, options);
|
|
3499
|
+
}
|
|
3500
|
+
/**
|
|
3501
|
+
* Fetch all automod rules for a server.
|
|
3502
|
+
*
|
|
3503
|
+
* @example
|
|
3504
|
+
* const rules = await client.fetchAutoModRules('server-id')
|
|
3505
|
+
*/
|
|
3506
|
+
fetchAutoModRules(serverId) {
|
|
3507
|
+
return this.automod.list(serverId);
|
|
3508
|
+
}
|
|
3509
|
+
/**
|
|
3510
|
+
* Fetch all channel categories for a server.
|
|
3511
|
+
*
|
|
3512
|
+
* @example
|
|
3513
|
+
* const cats = await client.fetchCategories('server-id')
|
|
3514
|
+
*/
|
|
3515
|
+
fetchCategories(serverId) {
|
|
3516
|
+
return this.categories.list(serverId);
|
|
3517
|
+
}
|
|
3518
|
+
/**
|
|
3519
|
+
* Fetch soundboard clips for a server.
|
|
3520
|
+
*
|
|
3521
|
+
* @example
|
|
3522
|
+
* const clips = await client.fetchSoundboard('server-id')
|
|
3523
|
+
*/
|
|
3524
|
+
fetchSoundboard(serverId) {
|
|
3525
|
+
return this.servers.listSoundboard(serverId);
|
|
3526
|
+
}
|
|
3527
|
+
/**
|
|
3528
|
+
* Fetch statistics for a server (member count, message count, etc.).
|
|
3529
|
+
*
|
|
3530
|
+
* @example
|
|
3531
|
+
* const stats = await client.fetchServerStats('server-id')
|
|
3532
|
+
* console.log(`${stats.onlineCount}/${stats.memberCount} online`)
|
|
3533
|
+
*/
|
|
3534
|
+
fetchServerStats(serverId) {
|
|
3535
|
+
return this.servers.getStats(serverId);
|
|
3536
|
+
}
|
|
3537
|
+
/**
|
|
3538
|
+
* Bulk delete up to 100 messages in a channel.
|
|
3539
|
+
* Requires the `messages.manage` scope.
|
|
3540
|
+
*
|
|
3541
|
+
* @example
|
|
3542
|
+
* const result = await client.bulkDelete('channel-id', messageIds)
|
|
3543
|
+
* console.log(`Deleted ${result.deleted} messages`)
|
|
3544
|
+
*/
|
|
3545
|
+
bulkDelete(channelId, messageIds) {
|
|
3546
|
+
return this.channels.bulkDelete(channelId, messageIds);
|
|
3547
|
+
}
|
|
2416
3548
|
// ─── Event fence ──────────────────────────────────────────────────────────────
|
|
2417
3549
|
/**
|
|
2418
3550
|
* Wait for a specific event to be emitted, optionally filtered.
|
|
@@ -2442,6 +3574,58 @@ var NovaClient = class extends import_node_events.EventEmitter {
|
|
|
2442
3574
|
this.on(event, handler);
|
|
2443
3575
|
});
|
|
2444
3576
|
}
|
|
3577
|
+
/**
|
|
3578
|
+
* Wait for the next message matching an optional filter.
|
|
3579
|
+
* Short for `waitFor('messageCreate', filter, timeoutMs)`.
|
|
3580
|
+
*
|
|
3581
|
+
* @example
|
|
3582
|
+
* // Wait for any message in a specific channel
|
|
3583
|
+
* const msg = await client.waitForMessage(
|
|
3584
|
+
* m => m.channelId === channelId && !m.isFromBot(),
|
|
3585
|
+
* 30_000,
|
|
3586
|
+
* )
|
|
3587
|
+
* console.log(msg.content)
|
|
3588
|
+
*/
|
|
3589
|
+
waitForMessage(filter, timeoutMs = 3e4) {
|
|
3590
|
+
return this.waitFor("messageCreate", filter, timeoutMs);
|
|
3591
|
+
}
|
|
3592
|
+
/**
|
|
3593
|
+
* Wait for the next button-click interaction matching an optional filter.
|
|
3594
|
+
* Short for `waitFor('interactionCreate', i => i.isButton() && filter(i), timeoutMs)`.
|
|
3595
|
+
*
|
|
3596
|
+
* @example
|
|
3597
|
+
* // Wait for any button on a specific message
|
|
3598
|
+
* const click = await client.waitForButton(
|
|
3599
|
+
* i => i.triggerMsgId === message.id,
|
|
3600
|
+
* 60_000,
|
|
3601
|
+
* )
|
|
3602
|
+
* await click.reply('Button clicked!')
|
|
3603
|
+
*/
|
|
3604
|
+
waitForButton(filter, timeoutMs = 3e4) {
|
|
3605
|
+
return this.waitFor(
|
|
3606
|
+
"interactionCreate",
|
|
3607
|
+
(i) => i.isButton() && (!filter || filter(i)),
|
|
3608
|
+
timeoutMs
|
|
3609
|
+
);
|
|
3610
|
+
}
|
|
3611
|
+
/**
|
|
3612
|
+
* Wait for the next select-menu interaction matching an optional filter.
|
|
3613
|
+
* Short for `waitFor('interactionCreate', i => i.isSelectMenu() && filter(i), timeoutMs)`.
|
|
3614
|
+
*
|
|
3615
|
+
* @example
|
|
3616
|
+
* const pick = await client.waitForSelectMenu(
|
|
3617
|
+
* i => i.customId === 'colour_pick',
|
|
3618
|
+
* 60_000,
|
|
3619
|
+
* )
|
|
3620
|
+
* await pick.reply(`You picked: ${pick.values.join(', ')}`)
|
|
3621
|
+
*/
|
|
3622
|
+
waitForSelectMenu(filter, timeoutMs = 3e4) {
|
|
3623
|
+
return this.waitFor(
|
|
3624
|
+
"interactionCreate",
|
|
3625
|
+
(i) => i.isSelectMenu() && (!filter || filter(i)),
|
|
3626
|
+
timeoutMs
|
|
3627
|
+
);
|
|
3628
|
+
}
|
|
2445
3629
|
/**
|
|
2446
3630
|
* Disconnect from the gateway and clean up.
|
|
2447
3631
|
*/
|
|
@@ -3809,47 +4993,1376 @@ function countdown(target) {
|
|
|
3809
4993
|
seconds: Math.floor(total % MINUTE / SECOND)
|
|
3810
4994
|
};
|
|
3811
4995
|
}
|
|
4996
|
+
|
|
4997
|
+
// src/structures/NovaCategory.ts
|
|
4998
|
+
var NovaCategory = class _NovaCategory {
|
|
4999
|
+
constructor(raw, categories) {
|
|
5000
|
+
this.id = raw.id;
|
|
5001
|
+
this.name = raw.name;
|
|
5002
|
+
this.position = raw.position;
|
|
5003
|
+
this.serverId = raw.serverId;
|
|
5004
|
+
this.createdAt = raw.createdAt;
|
|
5005
|
+
this._categories = categories;
|
|
5006
|
+
}
|
|
5007
|
+
// ─── Convenience methods ──────────────────────────────────────────────────
|
|
5008
|
+
/**
|
|
5009
|
+
* Edit this category's name and/or position.
|
|
5010
|
+
* Requires the `channels.manage` scope.
|
|
5011
|
+
*
|
|
5012
|
+
* @example
|
|
5013
|
+
* await cat.edit({ name: 'Lounges', position: 0 })
|
|
5014
|
+
*/
|
|
5015
|
+
async edit(options) {
|
|
5016
|
+
const updated = await this._categories.edit(this.id, options);
|
|
5017
|
+
return new _NovaCategory(updated, this._categories);
|
|
5018
|
+
}
|
|
5019
|
+
/**
|
|
5020
|
+
* Rename this category.
|
|
5021
|
+
* Requires the `channels.manage` scope.
|
|
5022
|
+
*
|
|
5023
|
+
* @example
|
|
5024
|
+
* await cat.rename('Lounges')
|
|
5025
|
+
*/
|
|
5026
|
+
rename(name) {
|
|
5027
|
+
return this.edit({ name });
|
|
5028
|
+
}
|
|
5029
|
+
/**
|
|
5030
|
+
* Move this category to a specific position.
|
|
5031
|
+
* Requires the `channels.manage` scope.
|
|
5032
|
+
*
|
|
5033
|
+
* @example
|
|
5034
|
+
* await cat.setPosition(0)
|
|
5035
|
+
*/
|
|
5036
|
+
setPosition(position) {
|
|
5037
|
+
return this.edit({ position });
|
|
5038
|
+
}
|
|
5039
|
+
/**
|
|
5040
|
+
* Delete this category.
|
|
5041
|
+
* Requires the `channels.manage` scope.
|
|
5042
|
+
*
|
|
5043
|
+
* @example
|
|
5044
|
+
* await cat.delete()
|
|
5045
|
+
*/
|
|
5046
|
+
async delete() {
|
|
5047
|
+
await this._categories.delete(this.id);
|
|
5048
|
+
}
|
|
5049
|
+
// ─── Serialisation ─────────────────────────────────────────────────────────
|
|
5050
|
+
toJSON() {
|
|
5051
|
+
return {
|
|
5052
|
+
id: this.id,
|
|
5053
|
+
name: this.name,
|
|
5054
|
+
position: this.position,
|
|
5055
|
+
serverId: this.serverId,
|
|
5056
|
+
createdAt: this.createdAt
|
|
5057
|
+
};
|
|
5058
|
+
}
|
|
5059
|
+
toString() {
|
|
5060
|
+
return `NovaCategory(${this.id}): ${this.name}`;
|
|
5061
|
+
}
|
|
5062
|
+
};
|
|
5063
|
+
|
|
5064
|
+
// src/builders/ForumPostBuilder.ts
|
|
5065
|
+
var ForumPostBuilder = class {
|
|
5066
|
+
constructor() {
|
|
5067
|
+
this._title = "";
|
|
5068
|
+
this._body = "";
|
|
5069
|
+
this._tags = [];
|
|
5070
|
+
}
|
|
5071
|
+
/**
|
|
5072
|
+
* Set the post title.
|
|
5073
|
+
*/
|
|
5074
|
+
setTitle(title) {
|
|
5075
|
+
this._title = title;
|
|
5076
|
+
return this;
|
|
5077
|
+
}
|
|
5078
|
+
/**
|
|
5079
|
+
* Set the post body / content.
|
|
5080
|
+
*/
|
|
5081
|
+
setBody(body) {
|
|
5082
|
+
this._body = body;
|
|
5083
|
+
return this;
|
|
5084
|
+
}
|
|
5085
|
+
/**
|
|
5086
|
+
* Add a tag to the post.
|
|
5087
|
+
* Tags are used to categorise forum posts.
|
|
5088
|
+
*/
|
|
5089
|
+
addTag(tag) {
|
|
5090
|
+
this._tags.push(tag);
|
|
5091
|
+
return this;
|
|
5092
|
+
}
|
|
5093
|
+
/**
|
|
5094
|
+
* Set all tags at once, replacing any previously added tags.
|
|
5095
|
+
*/
|
|
5096
|
+
setTags(tags) {
|
|
5097
|
+
this._tags = [...tags];
|
|
5098
|
+
return this;
|
|
5099
|
+
}
|
|
5100
|
+
/**
|
|
5101
|
+
* Validate and return the final `CreateForumPostOptions` object.
|
|
5102
|
+
*
|
|
5103
|
+
* @throws {Error} if title or body is missing.
|
|
5104
|
+
*/
|
|
5105
|
+
build() {
|
|
5106
|
+
if (!this._title.trim()) throw new Error("[ForumPostBuilder] title is required");
|
|
5107
|
+
if (!this._body.trim()) throw new Error("[ForumPostBuilder] body is required");
|
|
5108
|
+
return {
|
|
5109
|
+
title: this._title.trim(),
|
|
5110
|
+
body: this._body.trim(),
|
|
5111
|
+
tags: this._tags
|
|
5112
|
+
};
|
|
5113
|
+
}
|
|
5114
|
+
};
|
|
5115
|
+
|
|
5116
|
+
// src/builders/EventBuilder.ts
|
|
5117
|
+
var EventBuilder = class {
|
|
5118
|
+
constructor() {
|
|
5119
|
+
this._title = "";
|
|
5120
|
+
}
|
|
5121
|
+
/** Set the event title (required). */
|
|
5122
|
+
setTitle(title) {
|
|
5123
|
+
this._title = title;
|
|
5124
|
+
return this;
|
|
5125
|
+
}
|
|
5126
|
+
/** Set the event description. */
|
|
5127
|
+
setDescription(description) {
|
|
5128
|
+
this._description = description;
|
|
5129
|
+
return this;
|
|
5130
|
+
}
|
|
5131
|
+
/** Set a banner/cover image URL for the event. */
|
|
5132
|
+
setImage(url) {
|
|
5133
|
+
this._imageUrl = url;
|
|
5134
|
+
return this;
|
|
5135
|
+
}
|
|
5136
|
+
/** Set the physical or virtual location for the event. */
|
|
5137
|
+
setLocation(location) {
|
|
5138
|
+
this._location = location;
|
|
5139
|
+
return this;
|
|
5140
|
+
}
|
|
5141
|
+
/** Set when the event starts. Accepts a Date or ISO string. */
|
|
5142
|
+
setStartAt(date) {
|
|
5143
|
+
this._startAt = date instanceof Date ? date.toISOString() : date;
|
|
5144
|
+
return this;
|
|
5145
|
+
}
|
|
5146
|
+
/** Set when the event ends. Accepts a Date or ISO string. */
|
|
5147
|
+
setEndAt(date) {
|
|
5148
|
+
this._endAt = date instanceof Date ? date.toISOString() : date;
|
|
5149
|
+
return this;
|
|
5150
|
+
}
|
|
5151
|
+
/** Link the event to a specific channel. */
|
|
5152
|
+
setChannel(channelId) {
|
|
5153
|
+
this._channelId = channelId;
|
|
5154
|
+
return this;
|
|
5155
|
+
}
|
|
5156
|
+
/**
|
|
5157
|
+
* Validate and return the final `CreateEventOptions` object.
|
|
5158
|
+
*
|
|
5159
|
+
* @throws {Error} if title or startAt is missing.
|
|
5160
|
+
*/
|
|
5161
|
+
build() {
|
|
5162
|
+
if (!this._title.trim()) throw new Error("[EventBuilder] title is required");
|
|
5163
|
+
if (!this._startAt) throw new Error("[EventBuilder] startAt is required \u2014 call setStartAt()");
|
|
5164
|
+
return {
|
|
5165
|
+
title: this._title.trim(),
|
|
5166
|
+
...this._description !== void 0 ? { description: this._description } : {},
|
|
5167
|
+
...this._imageUrl !== void 0 ? { imageUrl: this._imageUrl } : {},
|
|
5168
|
+
...this._location !== void 0 ? { location: this._location } : {},
|
|
5169
|
+
startAt: this._startAt,
|
|
5170
|
+
...this._endAt !== void 0 ? { endAt: this._endAt } : {},
|
|
5171
|
+
...this._channelId !== void 0 ? { channelId: this._channelId } : {}
|
|
5172
|
+
};
|
|
5173
|
+
}
|
|
5174
|
+
};
|
|
5175
|
+
|
|
5176
|
+
// src/builders/RoleBuilder.ts
|
|
5177
|
+
var RoleBuilder = class {
|
|
5178
|
+
constructor() {
|
|
5179
|
+
this._name = "";
|
|
5180
|
+
}
|
|
5181
|
+
/** Set the role's display name (required). */
|
|
5182
|
+
setName(name) {
|
|
5183
|
+
this._name = name;
|
|
5184
|
+
return this;
|
|
5185
|
+
}
|
|
5186
|
+
/**
|
|
5187
|
+
* Set the role's accent colour.
|
|
5188
|
+
* @param color Hex string — e.g. `'#5865F2'` or `'5865F2'`
|
|
5189
|
+
*/
|
|
5190
|
+
setColor(color) {
|
|
5191
|
+
this._color = color.startsWith("#") ? color : `#${color}`;
|
|
5192
|
+
return this;
|
|
5193
|
+
}
|
|
5194
|
+
/**
|
|
5195
|
+
* Whether this role is shown separately in the member sidebar.
|
|
5196
|
+
* Default: `true` when called without arguments.
|
|
5197
|
+
*/
|
|
5198
|
+
setHoist(hoist = true) {
|
|
5199
|
+
this._hoist = hoist;
|
|
5200
|
+
return this;
|
|
5201
|
+
}
|
|
5202
|
+
/** Set a specific permission key to true or false. */
|
|
5203
|
+
addPermission(key, value = true) {
|
|
5204
|
+
if (!this._permissions) this._permissions = {};
|
|
5205
|
+
this._permissions[key] = value;
|
|
5206
|
+
return this;
|
|
5207
|
+
}
|
|
5208
|
+
/** Replace all permission overrides at once. */
|
|
5209
|
+
setPermissions(permissions) {
|
|
5210
|
+
this._permissions = { ...permissions };
|
|
5211
|
+
return this;
|
|
5212
|
+
}
|
|
5213
|
+
// ─── Common permission shorthands ─────────────────────────────────────────
|
|
5214
|
+
/** Grant the `sendMessages` permission. */
|
|
5215
|
+
allowSendMessages() {
|
|
5216
|
+
return this.addPermission("sendMessages");
|
|
5217
|
+
}
|
|
5218
|
+
/** Deny the `sendMessages` permission. */
|
|
5219
|
+
denySendMessages() {
|
|
5220
|
+
return this.addPermission("sendMessages", false);
|
|
5221
|
+
}
|
|
5222
|
+
/** Grant the `addReactions` permission. */
|
|
5223
|
+
allowAddReactions() {
|
|
5224
|
+
return this.addPermission("addReactions");
|
|
5225
|
+
}
|
|
5226
|
+
/** Grant the `manageMessages` permission (delete/pin messages). */
|
|
5227
|
+
allowManageMessages() {
|
|
5228
|
+
return this.addPermission("manageMessages");
|
|
5229
|
+
}
|
|
5230
|
+
/** Grant the `manageChannels` permission. */
|
|
5231
|
+
allowManageChannels() {
|
|
5232
|
+
return this.addPermission("manageChannels");
|
|
5233
|
+
}
|
|
5234
|
+
/** Grant the `kickMembers` permission. */
|
|
5235
|
+
allowKickMembers() {
|
|
5236
|
+
return this.addPermission("kickMembers");
|
|
5237
|
+
}
|
|
5238
|
+
/** Grant the `banMembers` permission. */
|
|
5239
|
+
allowBanMembers() {
|
|
5240
|
+
return this.addPermission("banMembers");
|
|
5241
|
+
}
|
|
5242
|
+
/** Grant the `manageServer` permission. */
|
|
5243
|
+
allowManageServer() {
|
|
5244
|
+
return this.addPermission("manageServer");
|
|
5245
|
+
}
|
|
5246
|
+
/** Grant the `manageRoles` permission. */
|
|
5247
|
+
allowManageRoles() {
|
|
5248
|
+
return this.addPermission("manageRoles");
|
|
5249
|
+
}
|
|
5250
|
+
/**
|
|
5251
|
+
* Validate and build the `RoleCreateOptions` object.
|
|
5252
|
+
*
|
|
5253
|
+
* @throws if name is not set.
|
|
5254
|
+
*/
|
|
5255
|
+
build() {
|
|
5256
|
+
if (!this._name.trim()) throw new Error("[RoleBuilder] name is required \u2014 call .setName()");
|
|
5257
|
+
return {
|
|
5258
|
+
name: this._name.trim(),
|
|
5259
|
+
...this._color !== void 0 ? { color: this._color } : {},
|
|
5260
|
+
...this._hoist !== void 0 ? { hoist: this._hoist } : {},
|
|
5261
|
+
...this._permissions !== void 0 ? { permissions: this._permissions } : {}
|
|
5262
|
+
};
|
|
5263
|
+
}
|
|
5264
|
+
};
|
|
5265
|
+
|
|
5266
|
+
// src/builders/ChannelBuilder.ts
|
|
5267
|
+
var ChannelBuilder = class {
|
|
5268
|
+
constructor() {
|
|
5269
|
+
this._name = "";
|
|
5270
|
+
this._type = "TEXT";
|
|
5271
|
+
}
|
|
5272
|
+
/** Set the channel name (required). No # prefix needed. */
|
|
5273
|
+
setName(name) {
|
|
5274
|
+
this._name = name;
|
|
5275
|
+
return this;
|
|
5276
|
+
}
|
|
5277
|
+
/**
|
|
5278
|
+
* Set the channel type.
|
|
5279
|
+
* @default 'TEXT'
|
|
5280
|
+
*/
|
|
5281
|
+
setType(type) {
|
|
5282
|
+
this._type = type;
|
|
5283
|
+
return this;
|
|
5284
|
+
}
|
|
5285
|
+
// ─── Type shorthands ──────────────────────────────────────────────────────
|
|
5286
|
+
/** Create a TEXT channel. */
|
|
5287
|
+
asText() {
|
|
5288
|
+
return this.setType("TEXT");
|
|
5289
|
+
}
|
|
5290
|
+
/** Create a VOICE channel. */
|
|
5291
|
+
asVoice() {
|
|
5292
|
+
return this.setType("VOICE");
|
|
5293
|
+
}
|
|
5294
|
+
/** Create an ANNOUNCEMENT channel. */
|
|
5295
|
+
asAnnouncement() {
|
|
5296
|
+
return this.setType("ANNOUNCEMENT");
|
|
5297
|
+
}
|
|
5298
|
+
/** Create a FORUM channel. */
|
|
5299
|
+
asForum() {
|
|
5300
|
+
return this.setType("FORUM");
|
|
5301
|
+
}
|
|
5302
|
+
/** Create a STAGE channel. */
|
|
5303
|
+
asStage() {
|
|
5304
|
+
return this.setType("STAGE");
|
|
5305
|
+
}
|
|
5306
|
+
// ─── Properties ───────────────────────────────────────────────────────────
|
|
5307
|
+
/** Set the channel topic / description. */
|
|
5308
|
+
setTopic(topic) {
|
|
5309
|
+
this._topic = topic;
|
|
5310
|
+
return this;
|
|
5311
|
+
}
|
|
5312
|
+
/** Set the channel's sort position. */
|
|
5313
|
+
setPosition(position) {
|
|
5314
|
+
this._position = position;
|
|
5315
|
+
return this;
|
|
5316
|
+
}
|
|
5317
|
+
/** Place the channel inside an existing category by its ID. */
|
|
5318
|
+
setCategory(categoryId) {
|
|
5319
|
+
this._categoryId = categoryId;
|
|
5320
|
+
return this;
|
|
5321
|
+
}
|
|
5322
|
+
/**
|
|
5323
|
+
* Set a slow-mode interval in seconds.
|
|
5324
|
+
* Members must wait this long between messages.
|
|
5325
|
+
* Pass `0` to disable.
|
|
5326
|
+
*/
|
|
5327
|
+
setSlowMode(seconds) {
|
|
5328
|
+
this._slowMode = seconds;
|
|
5329
|
+
return this;
|
|
5330
|
+
}
|
|
5331
|
+
/**
|
|
5332
|
+
* Mark the channel as private.
|
|
5333
|
+
* Private channels are only visible to members with explicit access.
|
|
5334
|
+
*/
|
|
5335
|
+
setPrivate(isPrivate = true) {
|
|
5336
|
+
this._isPrivate = isPrivate;
|
|
5337
|
+
return this;
|
|
5338
|
+
}
|
|
5339
|
+
/**
|
|
5340
|
+
* Validate and build the `CreateChannelOptions` object.
|
|
5341
|
+
*
|
|
5342
|
+
* @throws if name is not set.
|
|
5343
|
+
*/
|
|
5344
|
+
build() {
|
|
5345
|
+
if (!this._name.trim()) throw new Error("[ChannelBuilder] name is required \u2014 call .setName()");
|
|
5346
|
+
return {
|
|
5347
|
+
name: this._name.trim(),
|
|
5348
|
+
type: this._type,
|
|
5349
|
+
...this._topic !== void 0 ? { topic: this._topic } : {},
|
|
5350
|
+
...this._position !== void 0 ? { position: this._position } : {},
|
|
5351
|
+
...this._categoryId !== void 0 ? { categoryId: this._categoryId } : {},
|
|
5352
|
+
...this._slowMode !== void 0 ? { slowMode: this._slowMode } : {},
|
|
5353
|
+
...this._isPrivate !== void 0 ? { isPrivate: this._isPrivate } : {}
|
|
5354
|
+
};
|
|
5355
|
+
}
|
|
5356
|
+
};
|
|
5357
|
+
|
|
5358
|
+
// src/builders/InviteBuilder.ts
|
|
5359
|
+
var InviteBuilder = class {
|
|
5360
|
+
/**
|
|
5361
|
+
* Set the maximum number of times this invite can be used.
|
|
5362
|
+
* Pass `null` for unlimited uses.
|
|
5363
|
+
*/
|
|
5364
|
+
setMaxUses(maxUses) {
|
|
5365
|
+
this._maxUses = maxUses;
|
|
5366
|
+
return this;
|
|
5367
|
+
}
|
|
5368
|
+
/**
|
|
5369
|
+
* Set an absolute expiry date/time for this invite.
|
|
5370
|
+
* Pass a `Date`, an ISO string, or `null` to never expire.
|
|
5371
|
+
*/
|
|
5372
|
+
setExpiresAt(date) {
|
|
5373
|
+
if (date === null) {
|
|
5374
|
+
this._expiresAt = null;
|
|
5375
|
+
} else {
|
|
5376
|
+
this._expiresAt = date instanceof Date ? date.toISOString() : date;
|
|
5377
|
+
}
|
|
5378
|
+
return this;
|
|
5379
|
+
}
|
|
5380
|
+
/**
|
|
5381
|
+
* Set expiry as a duration from now.
|
|
5382
|
+
* @param ms Duration in milliseconds.
|
|
5383
|
+
*
|
|
5384
|
+
* @example
|
|
5385
|
+
* builder.expiresIn(7 * 24 * 60 * 60 * 1000) // 7 days
|
|
5386
|
+
*/
|
|
5387
|
+
expiresIn(ms) {
|
|
5388
|
+
this._expiresAt = new Date(Date.now() + ms).toISOString();
|
|
5389
|
+
return this;
|
|
5390
|
+
}
|
|
5391
|
+
/**
|
|
5392
|
+
* Create a one-time use invite (`maxUses = 1`).
|
|
5393
|
+
*/
|
|
5394
|
+
setOneTimeUse() {
|
|
5395
|
+
return this.setMaxUses(1);
|
|
5396
|
+
}
|
|
5397
|
+
/**
|
|
5398
|
+
* Create a permanent invite with no expiry or usage limit.
|
|
5399
|
+
*/
|
|
5400
|
+
setPermanent() {
|
|
5401
|
+
this._maxUses = null;
|
|
5402
|
+
this._expiresAt = null;
|
|
5403
|
+
return this;
|
|
5404
|
+
}
|
|
5405
|
+
/**
|
|
5406
|
+
* Build the `InviteCreateOptions` object.
|
|
5407
|
+
*/
|
|
5408
|
+
build() {
|
|
5409
|
+
return {
|
|
5410
|
+
...this._maxUses !== void 0 ? { maxUses: this._maxUses } : {},
|
|
5411
|
+
...this._expiresAt !== void 0 ? { expiresAt: this._expiresAt } : {}
|
|
5412
|
+
};
|
|
5413
|
+
}
|
|
5414
|
+
};
|
|
5415
|
+
|
|
5416
|
+
// src/builders/AutoModRuleBuilder.ts
|
|
5417
|
+
var AutoModRuleBuilder = class {
|
|
5418
|
+
constructor() {
|
|
5419
|
+
this._value = "";
|
|
5420
|
+
this._enabled = true;
|
|
5421
|
+
}
|
|
5422
|
+
/** Set the rule type explicitly. */
|
|
5423
|
+
setType(type) {
|
|
5424
|
+
this._type = type;
|
|
5425
|
+
return this;
|
|
5426
|
+
}
|
|
5427
|
+
/**
|
|
5428
|
+
* Set the blocked value (word or domain).
|
|
5429
|
+
*/
|
|
5430
|
+
setValue(value) {
|
|
5431
|
+
this._value = value;
|
|
5432
|
+
return this;
|
|
5433
|
+
}
|
|
5434
|
+
/**
|
|
5435
|
+
* Shorthand: set type to BLOCKED_WORD and optionally set the value.
|
|
5436
|
+
*
|
|
5437
|
+
* @example
|
|
5438
|
+
* builder.blockWord('badword')
|
|
5439
|
+
*/
|
|
5440
|
+
blockWord(word) {
|
|
5441
|
+
this._type = "BLOCKED_WORD";
|
|
5442
|
+
if (word !== void 0) this._value = word;
|
|
5443
|
+
return this;
|
|
5444
|
+
}
|
|
5445
|
+
/**
|
|
5446
|
+
* Shorthand: set type to BLOCKED_LINK and optionally set the domain.
|
|
5447
|
+
*
|
|
5448
|
+
* @example
|
|
5449
|
+
* builder.blockLink('spam.com')
|
|
5450
|
+
*/
|
|
5451
|
+
blockLink(domain) {
|
|
5452
|
+
this._type = "BLOCKED_LINK";
|
|
5453
|
+
if (domain !== void 0) this._value = domain;
|
|
5454
|
+
return this;
|
|
5455
|
+
}
|
|
5456
|
+
/**
|
|
5457
|
+
* Whether the rule is active immediately.
|
|
5458
|
+
* @default true
|
|
5459
|
+
*/
|
|
5460
|
+
setEnabled(enabled) {
|
|
5461
|
+
this._enabled = enabled;
|
|
5462
|
+
return this;
|
|
5463
|
+
}
|
|
5464
|
+
/**
|
|
5465
|
+
* Validate and build the `CreateAutoModRuleOptions` object.
|
|
5466
|
+
*
|
|
5467
|
+
* @throws if type or value is not set.
|
|
5468
|
+
*/
|
|
5469
|
+
build() {
|
|
5470
|
+
if (!this._type) {
|
|
5471
|
+
throw new Error("[AutoModRuleBuilder] type is required \u2014 call .setType(), .blockWord(), or .blockLink()");
|
|
5472
|
+
}
|
|
5473
|
+
if (!this._value.trim()) {
|
|
5474
|
+
throw new Error("[AutoModRuleBuilder] value is required \u2014 call .setValue(), .blockWord(word), or .blockLink(domain)");
|
|
5475
|
+
}
|
|
5476
|
+
return {
|
|
5477
|
+
type: this._type,
|
|
5478
|
+
value: this._value.trim(),
|
|
5479
|
+
enabled: this._enabled
|
|
5480
|
+
};
|
|
5481
|
+
}
|
|
5482
|
+
};
|
|
5483
|
+
|
|
5484
|
+
// src/builders/ContextMenuCommandBuilder.ts
|
|
5485
|
+
var ContextMenuCommandBuilder = class {
|
|
5486
|
+
constructor() {
|
|
5487
|
+
this._name = "";
|
|
5488
|
+
this._target = "MESSAGE";
|
|
5489
|
+
this._guildId = null;
|
|
5490
|
+
}
|
|
5491
|
+
/**
|
|
5492
|
+
* Display name of the command (shown in the context menu).
|
|
5493
|
+
* Max 32 characters. May contain spaces.
|
|
5494
|
+
*
|
|
5495
|
+
* @example
|
|
5496
|
+
* builder.setName('Report Message')
|
|
5497
|
+
*/
|
|
5498
|
+
setName(name) {
|
|
5499
|
+
this._name = name.trim();
|
|
5500
|
+
return this;
|
|
5501
|
+
}
|
|
5502
|
+
/**
|
|
5503
|
+
* Set whether the command targets messages or users.
|
|
5504
|
+
*
|
|
5505
|
+
* @example
|
|
5506
|
+
* builder.setTarget('USER')
|
|
5507
|
+
*/
|
|
5508
|
+
setTarget(target) {
|
|
5509
|
+
this._target = target;
|
|
5510
|
+
return this;
|
|
5511
|
+
}
|
|
5512
|
+
/**
|
|
5513
|
+
* Shorthand for `setTarget('MESSAGE')`.
|
|
5514
|
+
*
|
|
5515
|
+
* @example
|
|
5516
|
+
* builder.forMessages()
|
|
5517
|
+
*/
|
|
5518
|
+
forMessages() {
|
|
5519
|
+
return this.setTarget("MESSAGE");
|
|
5520
|
+
}
|
|
5521
|
+
/**
|
|
5522
|
+
* Shorthand for `setTarget('USER')`.
|
|
5523
|
+
*
|
|
5524
|
+
* @example
|
|
5525
|
+
* builder.forUsers()
|
|
5526
|
+
*/
|
|
5527
|
+
forUsers() {
|
|
5528
|
+
return this.setTarget("USER");
|
|
5529
|
+
}
|
|
5530
|
+
/**
|
|
5531
|
+
* Register this command only for a specific server (guild).
|
|
5532
|
+
* Omit (or pass `null`) to make the command available globally.
|
|
5533
|
+
*
|
|
5534
|
+
* @example
|
|
5535
|
+
* builder.setGuildId('server-id')
|
|
5536
|
+
*/
|
|
5537
|
+
setGuildId(guildId) {
|
|
5538
|
+
this._guildId = guildId;
|
|
5539
|
+
return this;
|
|
5540
|
+
}
|
|
5541
|
+
/**
|
|
5542
|
+
* Validate and return the final command definition object.
|
|
5543
|
+
* Throws if `name` has not been set.
|
|
5544
|
+
*/
|
|
5545
|
+
build() {
|
|
5546
|
+
if (!this._name) {
|
|
5547
|
+
throw new Error("[ContextMenuCommandBuilder] Command name is required");
|
|
5548
|
+
}
|
|
5549
|
+
return {
|
|
5550
|
+
name: this._name,
|
|
5551
|
+
target: this._target,
|
|
5552
|
+
guildId: this._guildId
|
|
5553
|
+
};
|
|
5554
|
+
}
|
|
5555
|
+
/** Alias for `build()`. */
|
|
5556
|
+
toJSON() {
|
|
5557
|
+
return this.build();
|
|
5558
|
+
}
|
|
5559
|
+
};
|
|
5560
|
+
|
|
5561
|
+
// src/utils/MessageCollector.ts
|
|
5562
|
+
var MessageCollector = class {
|
|
5563
|
+
constructor(emitter, options = {}) {
|
|
5564
|
+
this._emitter = emitter;
|
|
5565
|
+
this._options = {
|
|
5566
|
+
count: options.count ?? 1,
|
|
5567
|
+
timeout: options.timeout ?? 6e4,
|
|
5568
|
+
filter: options.filter ?? (() => true)
|
|
5569
|
+
};
|
|
5570
|
+
}
|
|
5571
|
+
/**
|
|
5572
|
+
* Start collecting messages.
|
|
5573
|
+
* Returns a promise that resolves with the collected `NovaMessage` array.
|
|
5574
|
+
*/
|
|
5575
|
+
run() {
|
|
5576
|
+
return new Promise((resolve) => {
|
|
5577
|
+
const collected = [];
|
|
5578
|
+
const cleanup = () => {
|
|
5579
|
+
clearTimeout(timer);
|
|
5580
|
+
this._emitter.off("messageCreate", handler);
|
|
5581
|
+
};
|
|
5582
|
+
const handler = (msg) => {
|
|
5583
|
+
if (!this._options.filter(msg)) return;
|
|
5584
|
+
collected.push(msg);
|
|
5585
|
+
if (collected.length >= this._options.count) {
|
|
5586
|
+
cleanup();
|
|
5587
|
+
resolve([...collected]);
|
|
5588
|
+
}
|
|
5589
|
+
};
|
|
5590
|
+
const timer = setTimeout(() => {
|
|
5591
|
+
this._emitter.off("messageCreate", handler);
|
|
5592
|
+
resolve([...collected]);
|
|
5593
|
+
}, this._options.timeout);
|
|
5594
|
+
this._emitter.on("messageCreate", handler);
|
|
5595
|
+
});
|
|
5596
|
+
}
|
|
5597
|
+
};
|
|
5598
|
+
|
|
5599
|
+
// src/utils/InteractionCollector.ts
|
|
5600
|
+
var InteractionCollector = class {
|
|
5601
|
+
constructor(emitter, options = {}) {
|
|
5602
|
+
this._emitter = emitter;
|
|
5603
|
+
this._options = {
|
|
5604
|
+
count: options.count ?? 1,
|
|
5605
|
+
timeout: options.timeout ?? 6e4,
|
|
5606
|
+
filter: options.filter ?? (() => true),
|
|
5607
|
+
messageId: options.messageId
|
|
5608
|
+
};
|
|
5609
|
+
}
|
|
5610
|
+
/**
|
|
5611
|
+
* Start collecting interactions.
|
|
5612
|
+
* Returns a promise that resolves with the collected `NovaInteraction` array.
|
|
5613
|
+
*/
|
|
5614
|
+
run() {
|
|
5615
|
+
return new Promise((resolve) => {
|
|
5616
|
+
const collected = [];
|
|
5617
|
+
const cleanup = () => {
|
|
5618
|
+
clearTimeout(timer);
|
|
5619
|
+
this._emitter.off("interactionCreate", handler);
|
|
5620
|
+
};
|
|
5621
|
+
const handler = (interaction) => {
|
|
5622
|
+
if (this._options.messageId && interaction.triggerMsgId !== this._options.messageId) return;
|
|
5623
|
+
if (!this._options.filter(interaction)) return;
|
|
5624
|
+
collected.push(interaction);
|
|
5625
|
+
if (collected.length >= this._options.count) {
|
|
5626
|
+
cleanup();
|
|
5627
|
+
resolve([...collected]);
|
|
5628
|
+
}
|
|
5629
|
+
};
|
|
5630
|
+
const timer = setTimeout(() => {
|
|
5631
|
+
this._emitter.off("interactionCreate", handler);
|
|
5632
|
+
resolve([...collected]);
|
|
5633
|
+
}, this._options.timeout);
|
|
5634
|
+
this._emitter.on("interactionCreate", handler);
|
|
5635
|
+
});
|
|
5636
|
+
}
|
|
5637
|
+
};
|
|
5638
|
+
|
|
5639
|
+
// src/utils/MentionParser.ts
|
|
5640
|
+
var MentionParser = class {
|
|
5641
|
+
// ─── Extraction ────────────────────────────────────────────────────────────
|
|
5642
|
+
/**
|
|
5643
|
+
* Extract all user IDs mentioned in the content (`<@userId>`).
|
|
5644
|
+
*
|
|
5645
|
+
* @example
|
|
5646
|
+
* MentionParser.userIds('Hello <@abc> and <@xyz>!') // ['abc', 'xyz']
|
|
5647
|
+
*/
|
|
5648
|
+
static userIds(content) {
|
|
5649
|
+
return [...content.matchAll(/<@([a-zA-Z0-9_-]+)>/g)].map((m) => m[1]);
|
|
5650
|
+
}
|
|
5651
|
+
/**
|
|
5652
|
+
* Extract all channel IDs mentioned in the content (`<#channelId>`).
|
|
5653
|
+
*
|
|
5654
|
+
* @example
|
|
5655
|
+
* MentionParser.channelIds('Go to <#general>!') // ['general']
|
|
5656
|
+
*/
|
|
5657
|
+
static channelIds(content) {
|
|
5658
|
+
return [...content.matchAll(/<#([a-zA-Z0-9_-]+)>/g)].map((m) => m[1]);
|
|
5659
|
+
}
|
|
5660
|
+
/**
|
|
5661
|
+
* Extract all role IDs mentioned in the content (`<&roleId>`).
|
|
5662
|
+
*
|
|
5663
|
+
* @example
|
|
5664
|
+
* MentionParser.roleIds('Paging <&mods>!') // ['mods']
|
|
5665
|
+
*/
|
|
5666
|
+
static roleIds(content) {
|
|
5667
|
+
return [...content.matchAll(/<&([a-zA-Z0-9_-]+)>/g)].map((m) => m[1]);
|
|
5668
|
+
}
|
|
5669
|
+
/**
|
|
5670
|
+
* Extract all custom emoji IDs mentioned in the content (`<:name:id>`).
|
|
5671
|
+
*
|
|
5672
|
+
* @example
|
|
5673
|
+
* MentionParser.emojiIds('Love it <:nova:12345>!')
|
|
5674
|
+
* // [{ name: 'nova', id: '12345' }]
|
|
5675
|
+
*/
|
|
5676
|
+
static emojiIds(content) {
|
|
5677
|
+
return [...content.matchAll(/<:([a-zA-Z0-9_]+):([a-zA-Z0-9_-]+)>/g)].map((m) => ({
|
|
5678
|
+
name: m[1],
|
|
5679
|
+
id: m[2]
|
|
5680
|
+
}));
|
|
5681
|
+
}
|
|
5682
|
+
// ─── Format ─────────────────────────────────────────────────────────────────
|
|
5683
|
+
/**
|
|
5684
|
+
* Format a user ID into a mention string `<@userId>`.
|
|
5685
|
+
*
|
|
5686
|
+
* @example
|
|
5687
|
+
* MentionParser.user('abc123') // '<@abc123>'
|
|
5688
|
+
*/
|
|
5689
|
+
static user(userId) {
|
|
5690
|
+
return `<@${userId}>`;
|
|
5691
|
+
}
|
|
5692
|
+
/**
|
|
5693
|
+
* Format a channel ID into a mention string `<#channelId>`.
|
|
5694
|
+
*
|
|
5695
|
+
* @example
|
|
5696
|
+
* MentionParser.channel('general') // '<#general>'
|
|
5697
|
+
*/
|
|
5698
|
+
static channel(channelId) {
|
|
5699
|
+
return `<#${channelId}>`;
|
|
5700
|
+
}
|
|
5701
|
+
/**
|
|
5702
|
+
* Format a role ID into a mention string `<&roleId>`.
|
|
5703
|
+
*
|
|
5704
|
+
* @example
|
|
5705
|
+
* MentionParser.role('mods') // '<&mods>'
|
|
5706
|
+
*/
|
|
5707
|
+
static role(roleId) {
|
|
5708
|
+
return `<&${roleId}>`;
|
|
5709
|
+
}
|
|
5710
|
+
/**
|
|
5711
|
+
* Format a custom emoji mention `<:name:id>`.
|
|
5712
|
+
*
|
|
5713
|
+
* @example
|
|
5714
|
+
* MentionParser.emoji('nova', '12345') // '<:nova:12345>'
|
|
5715
|
+
*/
|
|
5716
|
+
static emoji(name, id) {
|
|
5717
|
+
return `<:${name}:${id}>`;
|
|
5718
|
+
}
|
|
5719
|
+
// ─── Clean ──────────────────────────────────────────────────────────────────
|
|
5720
|
+
/**
|
|
5721
|
+
* Remove all mention tokens from `content` and return the cleaned string.
|
|
5722
|
+
*
|
|
5723
|
+
* @example
|
|
5724
|
+
* MentionParser.stripMentions('Hello <@u1> in <#c1>!')
|
|
5725
|
+
* // 'Hello in !'
|
|
5726
|
+
*/
|
|
5727
|
+
static stripMentions(content) {
|
|
5728
|
+
return content.replace(/<@[a-zA-Z0-9_-]+>/g, "").replace(/<#[a-zA-Z0-9_-]+>/g, "").replace(/<&[a-zA-Z0-9_-]+>/g, "").replace(/<:[a-zA-Z0-9_]+:[a-zA-Z0-9_-]+>/g, "");
|
|
5729
|
+
}
|
|
5730
|
+
/**
|
|
5731
|
+
* Returns `true` if `content` mentions at least one user.
|
|
5732
|
+
* Optionally checks for a specific `userId`.
|
|
5733
|
+
*
|
|
5734
|
+
* @example
|
|
5735
|
+
* MentionParser.hasMention('Hi <@u1>') // true
|
|
5736
|
+
* MentionParser.hasMention('Hi <@u1>', 'u1') // true
|
|
5737
|
+
* MentionParser.hasMention('Hi <@u1>', 'u2') // false
|
|
5738
|
+
*/
|
|
5739
|
+
static hasMention(content, userId) {
|
|
5740
|
+
if (userId) return content.includes(`<@${userId}>`);
|
|
5741
|
+
return /<@[a-zA-Z0-9_-]+>/.test(content);
|
|
5742
|
+
}
|
|
5743
|
+
/**
|
|
5744
|
+
* Returns `true` if `content` mentions a specific bot by its ID.
|
|
5745
|
+
*
|
|
5746
|
+
* @example
|
|
5747
|
+
* if (MentionParser.mentionsBotId(message.content, client.user.id)) {
|
|
5748
|
+
* await message.reply('You called?')
|
|
5749
|
+
* }
|
|
5750
|
+
*/
|
|
5751
|
+
static mentionsBotId(content, botId) {
|
|
5752
|
+
return content.includes(`<@${botId}>`);
|
|
5753
|
+
}
|
|
5754
|
+
};
|
|
5755
|
+
|
|
5756
|
+
// src/utils/EmbedPaginator.ts
|
|
5757
|
+
var EmbedPaginator = class {
|
|
5758
|
+
constructor(emitter, messages, interactions, options) {
|
|
5759
|
+
this.emitter = emitter;
|
|
5760
|
+
this.messages = messages;
|
|
5761
|
+
this.interactions = interactions;
|
|
5762
|
+
this.options = options;
|
|
5763
|
+
this.page = 0;
|
|
5764
|
+
const size = Math.max(1, options.pageSize ?? 10);
|
|
5765
|
+
const pages = [];
|
|
5766
|
+
for (let i = 0; i < options.items.length; i += size) {
|
|
5767
|
+
pages.push(options.items.slice(i, i + size));
|
|
5768
|
+
}
|
|
5769
|
+
this.pages = pages;
|
|
5770
|
+
}
|
|
5771
|
+
/** Total number of pages. */
|
|
5772
|
+
get totalPages() {
|
|
5773
|
+
return this.pages.length;
|
|
5774
|
+
}
|
|
5775
|
+
/**
|
|
5776
|
+
* Send the first page to the configured channel.
|
|
5777
|
+
* If there are multiple pages, attaches ◀ ▶ navigation buttons and
|
|
5778
|
+
* listens for clicks for up to `options.timeout` ms.
|
|
5779
|
+
*/
|
|
5780
|
+
async send() {
|
|
5781
|
+
if (this.pages.length === 0) {
|
|
5782
|
+
await this.messages.send(this.options.channelId, { content: "*Nothing to display.*" });
|
|
5783
|
+
return;
|
|
5784
|
+
}
|
|
5785
|
+
const msg = await this.messages.send(this.options.channelId, this._buildPayload());
|
|
5786
|
+
if (this.pages.length <= 1) return;
|
|
5787
|
+
const timeout = this.options.timeout ?? 6e4;
|
|
5788
|
+
const deadline = Date.now() + timeout;
|
|
5789
|
+
while (true) {
|
|
5790
|
+
const remaining = deadline - Date.now();
|
|
5791
|
+
if (remaining <= 0) break;
|
|
5792
|
+
const click = await this._awaitClick(msg.id, remaining);
|
|
5793
|
+
if (!click) break;
|
|
5794
|
+
if (click.customId === "_pg_prev" && this.page > 0) this.page--;
|
|
5795
|
+
else if (click.customId === "_pg_next" && this.page < this.pages.length - 1) this.page++;
|
|
5796
|
+
this.interactions.respond(click.id, { content: "\u200B", ephemeral: true }).catch(() => void 0);
|
|
5797
|
+
await this.messages.edit(msg.id, this._buildPayload());
|
|
5798
|
+
}
|
|
5799
|
+
}
|
|
5800
|
+
// ── Internal helpers ────────────────────────────────────────────────────────
|
|
5801
|
+
_awaitClick(msgId, timeoutMs) {
|
|
5802
|
+
return new Promise((resolve) => {
|
|
5803
|
+
const timer = setTimeout(() => {
|
|
5804
|
+
this.emitter.off("interactionCreate", handler);
|
|
5805
|
+
resolve(null);
|
|
5806
|
+
}, timeoutMs);
|
|
5807
|
+
const handler = (i) => {
|
|
5808
|
+
const isOurs = i.triggerMsgId === msgId && (i.customId === "_pg_prev" || i.customId === "_pg_next");
|
|
5809
|
+
const isAllowed = !this.options.userId || i.userId === this.options.userId;
|
|
5810
|
+
if (isOurs && isAllowed) {
|
|
5811
|
+
clearTimeout(timer);
|
|
5812
|
+
this.emitter.off("interactionCreate", handler);
|
|
5813
|
+
resolve({ id: i.id, customId: i.customId });
|
|
5814
|
+
}
|
|
5815
|
+
};
|
|
5816
|
+
this.emitter.on("interactionCreate", handler);
|
|
5817
|
+
});
|
|
5818
|
+
}
|
|
5819
|
+
_buildPayload() {
|
|
5820
|
+
const page = this.pages[this.page];
|
|
5821
|
+
const embed = this.options.renderPage(page, this.page, this.pages.length);
|
|
5822
|
+
if (this.options.showPageCounter !== false && this.pages.length > 1) {
|
|
5823
|
+
const counter = `Page ${this.page + 1} / ${this.pages.length}`;
|
|
5824
|
+
embed.footer = embed.footer ? `${embed.footer} \u2022 ${counter}` : counter;
|
|
5825
|
+
}
|
|
5826
|
+
const row = new ActionRowBuilder().addComponent(
|
|
5827
|
+
new ButtonBuilder().setCustomId("_pg_prev").setLabel("\u25C0").setStyle("secondary").setDisabled(this.page === 0)
|
|
5828
|
+
).addComponent(
|
|
5829
|
+
new ButtonBuilder().setCustomId("_pg_next").setLabel("\u25B6").setStyle("secondary").setDisabled(this.page === this.pages.length - 1)
|
|
5830
|
+
);
|
|
5831
|
+
return { embed, components: row.toJSON() };
|
|
5832
|
+
}
|
|
5833
|
+
};
|
|
5834
|
+
|
|
5835
|
+
// src/utils/ConfirmationDialog.ts
|
|
5836
|
+
var ConfirmationDialog = class {
|
|
5837
|
+
constructor(emitter, messages, interactions) {
|
|
5838
|
+
this.emitter = emitter;
|
|
5839
|
+
this.messages = messages;
|
|
5840
|
+
this.interactions = interactions;
|
|
5841
|
+
}
|
|
5842
|
+
/**
|
|
5843
|
+
* Send the confirmation prompt and await the user's choice.
|
|
5844
|
+
* Returns `true` for confirm, `false` for cancel or timeout.
|
|
5845
|
+
*/
|
|
5846
|
+
async ask(options) {
|
|
5847
|
+
const content = options.content ?? "Are you sure?";
|
|
5848
|
+
const confirmLabel = options.confirmLabel ?? "Confirm";
|
|
5849
|
+
const cancelLabel = options.cancelLabel ?? "Cancel";
|
|
5850
|
+
const timeout = options.timeout ?? 3e4;
|
|
5851
|
+
const row = new ActionRowBuilder().addComponent(
|
|
5852
|
+
new ButtonBuilder().setCustomId("_confirm_yes").setLabel(confirmLabel).setStyle("success")
|
|
5853
|
+
).addComponent(
|
|
5854
|
+
new ButtonBuilder().setCustomId("_confirm_no").setLabel(cancelLabel).setStyle("danger")
|
|
5855
|
+
);
|
|
5856
|
+
const msg = await this.messages.send(options.channelId, {
|
|
5857
|
+
content,
|
|
5858
|
+
components: row.toJSON()
|
|
5859
|
+
});
|
|
5860
|
+
const click = await this._awaitClick(msg.id, options.userId, timeout);
|
|
5861
|
+
const disabledRow = new ActionRowBuilder().addComponent(
|
|
5862
|
+
new ButtonBuilder().setCustomId("_confirm_yes").setLabel(confirmLabel).setStyle("success").setDisabled(true)
|
|
5863
|
+
).addComponent(
|
|
5864
|
+
new ButtonBuilder().setCustomId("_confirm_no").setLabel(cancelLabel).setStyle("danger").setDisabled(true)
|
|
5865
|
+
);
|
|
5866
|
+
await this.messages.edit(msg.id, { content, components: disabledRow.toJSON() }).catch(() => void 0);
|
|
5867
|
+
if (click) {
|
|
5868
|
+
this.interactions.respond(click.id, { content: "\u200B", ephemeral: true }).catch(() => void 0);
|
|
5869
|
+
return click.customId === "_confirm_yes";
|
|
5870
|
+
}
|
|
5871
|
+
return false;
|
|
5872
|
+
}
|
|
5873
|
+
_awaitClick(msgId, userId, timeoutMs) {
|
|
5874
|
+
return new Promise((resolve) => {
|
|
5875
|
+
const timer = setTimeout(() => {
|
|
5876
|
+
this.emitter.off("interactionCreate", handler);
|
|
5877
|
+
resolve(null);
|
|
5878
|
+
}, timeoutMs);
|
|
5879
|
+
const handler = (i) => {
|
|
5880
|
+
const isOurs = i.triggerMsgId === msgId && (i.customId === "_confirm_yes" || i.customId === "_confirm_no");
|
|
5881
|
+
const isAllowed = !userId || i.userId === userId;
|
|
5882
|
+
if (isOurs && isAllowed && typeof i.customId === "string") {
|
|
5883
|
+
clearTimeout(timer);
|
|
5884
|
+
this.emitter.off("interactionCreate", handler);
|
|
5885
|
+
resolve({ id: i.id, customId: i.customId });
|
|
5886
|
+
}
|
|
5887
|
+
};
|
|
5888
|
+
this.emitter.on("interactionCreate", handler);
|
|
5889
|
+
});
|
|
5890
|
+
}
|
|
5891
|
+
};
|
|
5892
|
+
|
|
5893
|
+
// src/utils/ArgumentParser.ts
|
|
5894
|
+
var ParsedArguments = class {
|
|
5895
|
+
constructor(positional, flags) {
|
|
5896
|
+
this.positional = positional;
|
|
5897
|
+
this._flags = flags;
|
|
5898
|
+
}
|
|
5899
|
+
/**
|
|
5900
|
+
* Whether a named flag is present (regardless of value).
|
|
5901
|
+
*
|
|
5902
|
+
* @example
|
|
5903
|
+
* args.has('notify') // true for --notify or --notify true
|
|
5904
|
+
*/
|
|
5905
|
+
has(flag) {
|
|
5906
|
+
return this._flags.has(flag);
|
|
5907
|
+
}
|
|
5908
|
+
/**
|
|
5909
|
+
* Get the string value of a named flag, or `null` if absent.
|
|
5910
|
+
*
|
|
5911
|
+
* @example
|
|
5912
|
+
* args.get('reason') // 'rule violation'
|
|
5913
|
+
*/
|
|
5914
|
+
get(flag) {
|
|
5915
|
+
return this._flags.get(flag) ?? null;
|
|
5916
|
+
}
|
|
5917
|
+
/**
|
|
5918
|
+
* Get the string value of a named flag, throwing if missing.
|
|
5919
|
+
*
|
|
5920
|
+
* @example
|
|
5921
|
+
* const reason = args.require('reason') // throws if --reason not supplied
|
|
5922
|
+
*/
|
|
5923
|
+
require(flag) {
|
|
5924
|
+
const v = this._flags.get(flag);
|
|
5925
|
+
if (v == null) throw new Error(`[ArgumentParser] Required flag "--${flag}" is missing`);
|
|
5926
|
+
return v;
|
|
5927
|
+
}
|
|
5928
|
+
/**
|
|
5929
|
+
* Parse the flag value as an integer, or `null` if absent / not a number.
|
|
5930
|
+
*
|
|
5931
|
+
* @example
|
|
5932
|
+
* args.getInt('days') // 7 from '--days 7'
|
|
5933
|
+
*/
|
|
5934
|
+
getInt(flag) {
|
|
5935
|
+
const v = this._flags.get(flag);
|
|
5936
|
+
if (v == null) return null;
|
|
5937
|
+
const n = parseInt(v, 10);
|
|
5938
|
+
return isNaN(n) ? null : n;
|
|
5939
|
+
}
|
|
5940
|
+
/**
|
|
5941
|
+
* Parse the flag value as a float, or `null` if absent / not a number.
|
|
5942
|
+
*/
|
|
5943
|
+
getFloat(flag) {
|
|
5944
|
+
const v = this._flags.get(flag);
|
|
5945
|
+
if (v == null) return null;
|
|
5946
|
+
const n = parseFloat(v);
|
|
5947
|
+
return isNaN(n) ? null : n;
|
|
5948
|
+
}
|
|
5949
|
+
/**
|
|
5950
|
+
* Get a positional argument by index (0-based), or `null` if absent.
|
|
5951
|
+
*
|
|
5952
|
+
* @example
|
|
5953
|
+
* args.at(0) // first positional token
|
|
5954
|
+
*/
|
|
5955
|
+
at(index) {
|
|
5956
|
+
return this.positional[index] ?? null;
|
|
5957
|
+
}
|
|
5958
|
+
/**
|
|
5959
|
+
* Get positional argument at `index` as an integer, or `null`.
|
|
5960
|
+
*
|
|
5961
|
+
* @example
|
|
5962
|
+
* args.getInt(1) // 7 when positional is ['nick123', '7']
|
|
5963
|
+
*/
|
|
5964
|
+
getIntAt(index) {
|
|
5965
|
+
const v = this.positional[index];
|
|
5966
|
+
if (v == null) return null;
|
|
5967
|
+
const n = parseInt(v, 10);
|
|
5968
|
+
return isNaN(n) ? null : n;
|
|
5969
|
+
}
|
|
5970
|
+
/**
|
|
5971
|
+
* All flag names that were parsed.
|
|
5972
|
+
*
|
|
5973
|
+
* @example
|
|
5974
|
+
* args.flags() // ['reason', 'notify']
|
|
5975
|
+
*/
|
|
5976
|
+
flags() {
|
|
5977
|
+
return [...this._flags.keys()];
|
|
5978
|
+
}
|
|
5979
|
+
toJSON() {
|
|
5980
|
+
return {
|
|
5981
|
+
positional: this.positional,
|
|
5982
|
+
flags: Object.fromEntries(this._flags)
|
|
5983
|
+
};
|
|
5984
|
+
}
|
|
5985
|
+
};
|
|
5986
|
+
var ArgumentParser = class _ArgumentParser {
|
|
5987
|
+
/**
|
|
5988
|
+
* Parse a raw string of arguments.
|
|
5989
|
+
* Returns a `ParsedArguments` instance.
|
|
5990
|
+
*/
|
|
5991
|
+
static parse(input) {
|
|
5992
|
+
const positional = [];
|
|
5993
|
+
const flags = /* @__PURE__ */ new Map();
|
|
5994
|
+
const tokens = _ArgumentParser._tokenise(input);
|
|
5995
|
+
let i = 0;
|
|
5996
|
+
while (i < tokens.length) {
|
|
5997
|
+
const token = tokens[i];
|
|
5998
|
+
if (token.startsWith("--")) {
|
|
5999
|
+
const key = token.slice(2);
|
|
6000
|
+
const next = tokens[i + 1];
|
|
6001
|
+
if (next && !next.startsWith("-")) {
|
|
6002
|
+
flags.set(key, next);
|
|
6003
|
+
i += 2;
|
|
6004
|
+
} else {
|
|
6005
|
+
flags.set(key, "true");
|
|
6006
|
+
i++;
|
|
6007
|
+
}
|
|
6008
|
+
} else if (token.startsWith("-") && token.length === 2) {
|
|
6009
|
+
flags.set(token.slice(1), "true");
|
|
6010
|
+
i++;
|
|
6011
|
+
} else {
|
|
6012
|
+
positional.push(token);
|
|
6013
|
+
i++;
|
|
6014
|
+
}
|
|
6015
|
+
}
|
|
6016
|
+
return new ParsedArguments(positional, flags);
|
|
6017
|
+
}
|
|
6018
|
+
/**
|
|
6019
|
+
* Strip a user mention like `<@123456>` from the start of the input string
|
|
6020
|
+
* and return the remainder trimmed. Returns the original string unchanged if
|
|
6021
|
+
* no leading mention is found.
|
|
6022
|
+
*
|
|
6023
|
+
* @example
|
|
6024
|
+
* ArgumentParser.stripMention('<@98765> hello world') // 'hello world'
|
|
6025
|
+
*/
|
|
6026
|
+
static stripMention(input) {
|
|
6027
|
+
return input.replace(/^<@!?\d+>\s*/, "").trim();
|
|
6028
|
+
}
|
|
6029
|
+
/**
|
|
6030
|
+
* Split `input` into tokens. Quoted strings are treated as single tokens.
|
|
6031
|
+
*/
|
|
6032
|
+
static _tokenise(input) {
|
|
6033
|
+
const tokens = [];
|
|
6034
|
+
let current = "";
|
|
6035
|
+
let inDouble = false;
|
|
6036
|
+
let inSingle = false;
|
|
6037
|
+
for (let i = 0; i < input.length; i++) {
|
|
6038
|
+
const ch = input[i];
|
|
6039
|
+
if (ch === '"' && !inSingle) {
|
|
6040
|
+
inDouble = !inDouble;
|
|
6041
|
+
continue;
|
|
6042
|
+
}
|
|
6043
|
+
if (ch === "'" && !inDouble) {
|
|
6044
|
+
inSingle = !inSingle;
|
|
6045
|
+
continue;
|
|
6046
|
+
}
|
|
6047
|
+
if (ch === " " && !inDouble && !inSingle) {
|
|
6048
|
+
if (current.length > 0) {
|
|
6049
|
+
tokens.push(current);
|
|
6050
|
+
current = "";
|
|
6051
|
+
}
|
|
6052
|
+
continue;
|
|
6053
|
+
}
|
|
6054
|
+
current += ch;
|
|
6055
|
+
}
|
|
6056
|
+
if (current.length > 0) tokens.push(current);
|
|
6057
|
+
return tokens;
|
|
6058
|
+
}
|
|
6059
|
+
};
|
|
6060
|
+
|
|
6061
|
+
// src/utils/CacheMap.ts
|
|
6062
|
+
var CacheMap = class {
|
|
6063
|
+
constructor() {
|
|
6064
|
+
this._store = /* @__PURE__ */ new Map();
|
|
6065
|
+
}
|
|
6066
|
+
/**
|
|
6067
|
+
* Store a value.
|
|
6068
|
+
*
|
|
6069
|
+
* @param key - Cache key.
|
|
6070
|
+
* @param value - Value to store.
|
|
6071
|
+
* @param ttlMs - Optional time-to-live in milliseconds. Omit for permanent storage.
|
|
6072
|
+
*/
|
|
6073
|
+
set(key, value, ttlMs) {
|
|
6074
|
+
this._store.set(key, {
|
|
6075
|
+
value,
|
|
6076
|
+
expiresAt: ttlMs != null ? Date.now() + ttlMs : null
|
|
6077
|
+
});
|
|
6078
|
+
return this;
|
|
6079
|
+
}
|
|
6080
|
+
/**
|
|
6081
|
+
* Retrieve a value, or `undefined` if absent or expired.
|
|
6082
|
+
* Expired entries are automatically deleted on access.
|
|
6083
|
+
*/
|
|
6084
|
+
get(key) {
|
|
6085
|
+
const entry = this._store.get(key);
|
|
6086
|
+
if (!entry) return void 0;
|
|
6087
|
+
if (entry.expiresAt !== null && Date.now() >= entry.expiresAt) {
|
|
6088
|
+
this._store.delete(key);
|
|
6089
|
+
return void 0;
|
|
6090
|
+
}
|
|
6091
|
+
return entry.value;
|
|
6092
|
+
}
|
|
6093
|
+
/**
|
|
6094
|
+
* Check if a live (non-expired) entry exists for this key.
|
|
6095
|
+
*/
|
|
6096
|
+
has(key) {
|
|
6097
|
+
return this.get(key) !== void 0;
|
|
6098
|
+
}
|
|
6099
|
+
/**
|
|
6100
|
+
* Delete an entry.
|
|
6101
|
+
* Returns `true` if the entry existed (even if it was expired).
|
|
6102
|
+
*/
|
|
6103
|
+
delete(key) {
|
|
6104
|
+
return this._store.delete(key);
|
|
6105
|
+
}
|
|
6106
|
+
/** Remove all entries. */
|
|
6107
|
+
clear() {
|
|
6108
|
+
this._store.clear();
|
|
6109
|
+
}
|
|
6110
|
+
/**
|
|
6111
|
+
* Number of **live** (non-expired) entries.
|
|
6112
|
+
* This prunes expired entries as a side-effect.
|
|
6113
|
+
*/
|
|
6114
|
+
get size() {
|
|
6115
|
+
this.prune();
|
|
6116
|
+
return this._store.size;
|
|
6117
|
+
}
|
|
6118
|
+
/**
|
|
6119
|
+
* Remove all expired entries immediately.
|
|
6120
|
+
* Useful to call occasionally to free memory.
|
|
6121
|
+
*
|
|
6122
|
+
* @example
|
|
6123
|
+
* // Prune every 10 minutes
|
|
6124
|
+
* setInterval(() => cache.prune(), 10 * 60_000)
|
|
6125
|
+
*/
|
|
6126
|
+
prune() {
|
|
6127
|
+
const now = Date.now();
|
|
6128
|
+
let removed = 0;
|
|
6129
|
+
for (const [key, entry] of this._store) {
|
|
6130
|
+
if (entry.expiresAt !== null && now >= entry.expiresAt) {
|
|
6131
|
+
this._store.delete(key);
|
|
6132
|
+
removed++;
|
|
6133
|
+
}
|
|
6134
|
+
}
|
|
6135
|
+
return removed;
|
|
6136
|
+
}
|
|
6137
|
+
/**
|
|
6138
|
+
* Return all **live** keys.
|
|
6139
|
+
*/
|
|
6140
|
+
keys() {
|
|
6141
|
+
this.prune();
|
|
6142
|
+
return [...this._store.keys()];
|
|
6143
|
+
}
|
|
6144
|
+
/**
|
|
6145
|
+
* Return all **live** values.
|
|
6146
|
+
*/
|
|
6147
|
+
values() {
|
|
6148
|
+
this.prune();
|
|
6149
|
+
return [...this._store.values()].map((e) => e.value);
|
|
6150
|
+
}
|
|
6151
|
+
/**
|
|
6152
|
+
* Return all **live** `[key, value]` pairs.
|
|
6153
|
+
*/
|
|
6154
|
+
entries() {
|
|
6155
|
+
this.prune();
|
|
6156
|
+
return [...this._store.entries()].map(([k, e]) => [k, e.value]);
|
|
6157
|
+
}
|
|
6158
|
+
/**
|
|
6159
|
+
* Get a value or compute & cache it if missing.
|
|
6160
|
+
* Very useful for "cache-aside" data loading.
|
|
6161
|
+
*
|
|
6162
|
+
* @param key - Cache key.
|
|
6163
|
+
* @param loader - Async function that produces the value when the cache is cold.
|
|
6164
|
+
* @param ttlMs - Optional TTL to apply to the newly cached value.
|
|
6165
|
+
*
|
|
6166
|
+
* @example
|
|
6167
|
+
* const profile = await cache.getOrSet(userId, () => client.fetchUserProfile(userId), 60_000)
|
|
6168
|
+
*/
|
|
6169
|
+
async getOrSet(key, loader, ttlMs) {
|
|
6170
|
+
const existing = this.get(key);
|
|
6171
|
+
if (existing !== void 0) return existing;
|
|
6172
|
+
const value = await loader();
|
|
6173
|
+
this.set(key, value, ttlMs);
|
|
6174
|
+
return value;
|
|
6175
|
+
}
|
|
6176
|
+
/**
|
|
6177
|
+
* Return the number of milliseconds until a key expires.
|
|
6178
|
+
* Returns `null` if the key has no TTL, `0` if it is already expired.
|
|
6179
|
+
*/
|
|
6180
|
+
ttl(key) {
|
|
6181
|
+
const entry = this._store.get(key);
|
|
6182
|
+
if (!entry) return null;
|
|
6183
|
+
if (entry.expiresAt === null) return null;
|
|
6184
|
+
return Math.max(0, entry.expiresAt - Date.now());
|
|
6185
|
+
}
|
|
6186
|
+
[Symbol.iterator]() {
|
|
6187
|
+
return this.entries()[Symbol.iterator]();
|
|
6188
|
+
}
|
|
6189
|
+
};
|
|
6190
|
+
|
|
6191
|
+
// src/utils/EventScheduler.ts
|
|
6192
|
+
var _idCounter = 0;
|
|
6193
|
+
function nextId() {
|
|
6194
|
+
return `task_${++_idCounter}`;
|
|
6195
|
+
}
|
|
6196
|
+
var EventScheduler = class {
|
|
6197
|
+
constructor() {
|
|
6198
|
+
this._tasks = /* @__PURE__ */ new Map();
|
|
6199
|
+
}
|
|
6200
|
+
/**
|
|
6201
|
+
* Schedule a one-shot task to run after `delayMs` milliseconds.
|
|
6202
|
+
* Returns a task ID that can be passed to `cancel()`.
|
|
6203
|
+
*
|
|
6204
|
+
* @example
|
|
6205
|
+
* const id = scheduler.schedule(5_000, () => console.log('5 seconds later'))
|
|
6206
|
+
* // Change your mind:
|
|
6207
|
+
* scheduler.cancel(id)
|
|
6208
|
+
*/
|
|
6209
|
+
schedule(delayMs, fn) {
|
|
6210
|
+
const id = nextId();
|
|
6211
|
+
const handle = setTimeout(() => {
|
|
6212
|
+
this._tasks.delete(id);
|
|
6213
|
+
this._run(fn, id);
|
|
6214
|
+
}, delayMs);
|
|
6215
|
+
this._tasks.set(id, { id, handle, type: "once" });
|
|
6216
|
+
return id;
|
|
6217
|
+
}
|
|
6218
|
+
/**
|
|
6219
|
+
* Schedule a one-shot task to run at a specific `Date`.
|
|
6220
|
+
* If the date is in the past, the callback fires on the next event-loop tick.
|
|
6221
|
+
*
|
|
6222
|
+
* @example
|
|
6223
|
+
* const nextMidnight = new Date()
|
|
6224
|
+
* nextMidnight.setHours(24, 0, 0, 0)
|
|
6225
|
+
* scheduler.scheduleAt(nextMidnight, () => console.log('Midnight!'))
|
|
6226
|
+
*/
|
|
6227
|
+
scheduleAt(date, fn) {
|
|
6228
|
+
const delay = Math.max(0, date.getTime() - Date.now());
|
|
6229
|
+
return this.schedule(delay, fn);
|
|
6230
|
+
}
|
|
6231
|
+
/**
|
|
6232
|
+
* Schedule a recurring task that fires every `intervalMs` milliseconds.
|
|
6233
|
+
* Returns a task ID that can be passed to `cancel()`.
|
|
6234
|
+
*
|
|
6235
|
+
* @example
|
|
6236
|
+
* // Check incoming messages every minute
|
|
6237
|
+
* const id = scheduler.repeat(60_000, () => checkForAnnouncements())
|
|
6238
|
+
*/
|
|
6239
|
+
repeat(intervalMs, fn) {
|
|
6240
|
+
const id = nextId();
|
|
6241
|
+
const handle = setInterval(() => this._run(fn, id), intervalMs);
|
|
6242
|
+
this._tasks.set(id, { id, handle, type: "repeat" });
|
|
6243
|
+
return id;
|
|
6244
|
+
}
|
|
6245
|
+
/**
|
|
6246
|
+
* Cancel a previously scheduled task by its ID.
|
|
6247
|
+
* Returns `true` if the task existed, `false` if it had already fired or
|
|
6248
|
+
* was not found.
|
|
6249
|
+
*
|
|
6250
|
+
* @example
|
|
6251
|
+
* const id = scheduler.schedule(30_000, doSomething)
|
|
6252
|
+
* // …maybe cancel it:
|
|
6253
|
+
* scheduler.cancel(id)
|
|
6254
|
+
*/
|
|
6255
|
+
cancel(id) {
|
|
6256
|
+
const task = this._tasks.get(id);
|
|
6257
|
+
if (!task) return false;
|
|
6258
|
+
if (task.type === "once") clearTimeout(task.handle);
|
|
6259
|
+
else clearInterval(task.handle);
|
|
6260
|
+
this._tasks.delete(id);
|
|
6261
|
+
return true;
|
|
6262
|
+
}
|
|
6263
|
+
/**
|
|
6264
|
+
* Cancel all pending tasks.
|
|
6265
|
+
* Useful during graceful shutdown.
|
|
6266
|
+
*
|
|
6267
|
+
* @example
|
|
6268
|
+
* client.once('disconnect', () => scheduler.cancelAll())
|
|
6269
|
+
*/
|
|
6270
|
+
cancelAll() {
|
|
6271
|
+
for (const id of this._tasks.keys()) this.cancel(id);
|
|
6272
|
+
}
|
|
6273
|
+
/**
|
|
6274
|
+
* Number of currently active (pending or recurring) tasks.
|
|
6275
|
+
*/
|
|
6276
|
+
get pendingCount() {
|
|
6277
|
+
return this._tasks.size;
|
|
6278
|
+
}
|
|
6279
|
+
/**
|
|
6280
|
+
* IDs of all currently registered tasks.
|
|
6281
|
+
*/
|
|
6282
|
+
taskIds() {
|
|
6283
|
+
return [...this._tasks.keys()];
|
|
6284
|
+
}
|
|
6285
|
+
_run(fn, id) {
|
|
6286
|
+
try {
|
|
6287
|
+
const result = fn();
|
|
6288
|
+
if (result && typeof result.catch === "function") {
|
|
6289
|
+
;
|
|
6290
|
+
result.catch((e) => {
|
|
6291
|
+
console.error(`[EventScheduler] Task ${id} threw:`, e);
|
|
6292
|
+
});
|
|
6293
|
+
}
|
|
6294
|
+
} catch (e) {
|
|
6295
|
+
console.error(`[EventScheduler] Task ${id} threw:`, e);
|
|
6296
|
+
}
|
|
6297
|
+
}
|
|
6298
|
+
};
|
|
3812
6299
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3813
6300
|
0 && (module.exports = {
|
|
3814
6301
|
ActionRowBuilder,
|
|
6302
|
+
ArgumentParser,
|
|
3815
6303
|
AuditLogAPI,
|
|
6304
|
+
AutoModAPI,
|
|
6305
|
+
AutoModRuleBuilder,
|
|
3816
6306
|
ButtonBuilder,
|
|
6307
|
+
CacheMap,
|
|
6308
|
+
CategoriesAPI,
|
|
6309
|
+
ChannelBuilder,
|
|
3817
6310
|
ChannelsAPI,
|
|
3818
6311
|
Collection,
|
|
3819
6312
|
CommandsAPI,
|
|
6313
|
+
ConfirmationDialog,
|
|
6314
|
+
ContextMenuCommandBuilder,
|
|
3820
6315
|
Cooldown,
|
|
3821
6316
|
CooldownManager,
|
|
3822
6317
|
EmbedBuilder,
|
|
6318
|
+
EmbedPaginator,
|
|
6319
|
+
EventBuilder,
|
|
6320
|
+
EventScheduler,
|
|
6321
|
+
EventsAPI,
|
|
6322
|
+
ForumAPI,
|
|
6323
|
+
ForumPostBuilder,
|
|
3823
6324
|
HttpClient,
|
|
6325
|
+
InteractionCollector,
|
|
3824
6326
|
InteractionOptions,
|
|
3825
6327
|
InteractionsAPI,
|
|
6328
|
+
InviteBuilder,
|
|
3826
6329
|
InvitesAPI,
|
|
3827
6330
|
Logger,
|
|
3828
6331
|
MembersAPI,
|
|
6332
|
+
MentionParser,
|
|
3829
6333
|
MessageBuilder,
|
|
6334
|
+
MessageCollector,
|
|
3830
6335
|
MessagesAPI,
|
|
3831
6336
|
ModalBuilder,
|
|
6337
|
+
NovaBan,
|
|
6338
|
+
NovaCategory,
|
|
3832
6339
|
NovaChannel,
|
|
3833
6340
|
NovaClient,
|
|
6341
|
+
NovaForumPost,
|
|
3834
6342
|
NovaInteraction,
|
|
3835
6343
|
NovaInvite,
|
|
3836
6344
|
NovaMember,
|
|
3837
6345
|
NovaMessage,
|
|
3838
6346
|
NovaRole,
|
|
6347
|
+
NovaServerEvent,
|
|
3839
6348
|
NovaServerWrapper,
|
|
6349
|
+
NovaWarning,
|
|
3840
6350
|
NovaWebhook,
|
|
3841
6351
|
Paginator,
|
|
6352
|
+
ParsedArguments,
|
|
3842
6353
|
Permissions,
|
|
3843
6354
|
PermissionsAPI,
|
|
3844
6355
|
PermissionsBitfield,
|
|
3845
6356
|
PollBuilder,
|
|
3846
6357
|
ReactionsAPI,
|
|
6358
|
+
RoleBuilder,
|
|
3847
6359
|
RolesAPI,
|
|
3848
6360
|
SelectMenuBuilder,
|
|
3849
6361
|
ServersAPI,
|
|
3850
6362
|
SlashCommandBuilder,
|
|
3851
6363
|
SlashCommandOptionBuilder,
|
|
3852
6364
|
TextInputBuilder,
|
|
6365
|
+
UsersAPI,
|
|
3853
6366
|
WebhooksAPI,
|
|
3854
6367
|
countdown,
|
|
3855
6368
|
formatDuration,
|