@fluxerjs/core 1.2.1 → 1.2.3
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 +134 -37
- package/dist/index.d.ts +134 -37
- package/dist/index.js +244 -100
- package/dist/index.mjs +227 -81
- package/package.json +8 -8
package/dist/index.mjs
CHANGED
|
@@ -86,6 +86,7 @@ function buildSendBody(options) {
|
|
|
86
86
|
filename: f.filename ?? f.name
|
|
87
87
|
}));
|
|
88
88
|
}
|
|
89
|
+
if (body.flags !== void 0) result.flags = body.flags;
|
|
89
90
|
return result;
|
|
90
91
|
}
|
|
91
92
|
|
|
@@ -99,7 +100,7 @@ var Base = class {
|
|
|
99
100
|
|
|
100
101
|
// src/structures/Message.ts
|
|
101
102
|
import { Collection as Collection2 } from "@fluxerjs/collection";
|
|
102
|
-
import { MessageType, Routes } from "@fluxerjs/types";
|
|
103
|
+
import { MessageType, MessageFlags, Routes } from "@fluxerjs/types";
|
|
103
104
|
import { EmbedBuilder as EmbedBuilder2 } from "@fluxerjs/builders";
|
|
104
105
|
|
|
105
106
|
// src/util/ReactionCollector.ts
|
|
@@ -237,7 +238,10 @@ var Message = class _Message extends Base {
|
|
|
237
238
|
mentionRoles;
|
|
238
239
|
/** Client-side nonce for acknowledgment. Null if not provided. */
|
|
239
240
|
nonce;
|
|
240
|
-
/**
|
|
241
|
+
/**
|
|
242
|
+
* Channel where this message was sent. Resolved from cache; null if not cached.
|
|
243
|
+
* Messages can only exist in text-based channels (text, DM, announcement), so this always has send() when non-null.
|
|
244
|
+
*/
|
|
241
245
|
get channel() {
|
|
242
246
|
return this.client.channels.get(this.channelId) ?? null;
|
|
243
247
|
}
|
|
@@ -299,12 +303,8 @@ var Message = class _Message extends Base {
|
|
|
299
303
|
* await message.send({ content: 'File', files: [{ name: 'data.txt', data }] });
|
|
300
304
|
*/
|
|
301
305
|
async send(options) {
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
const files = opts.files?.length ? await resolveMessageFiles(opts.files) : void 0;
|
|
305
|
-
const postOptions = files?.length ? { body, files } : { body };
|
|
306
|
-
const data = await this.client.rest.post(Routes.channelMessages(this.channelId), postOptions);
|
|
307
|
-
return new _Message(this.client, data);
|
|
306
|
+
const payload = await _Message._createMessageBody(options);
|
|
307
|
+
return this._send(payload);
|
|
308
308
|
}
|
|
309
309
|
/**
|
|
310
310
|
* Send a message to a specific channel. Use for logging, forwarding, or sending to another channel in the guild.
|
|
@@ -319,25 +319,46 @@ var Message = class _Message extends Base {
|
|
|
319
319
|
}
|
|
320
320
|
/**
|
|
321
321
|
* Reply to this message (shows as a reply in the client).
|
|
322
|
-
* @param options - Text content or object with content, embeds, and/or
|
|
322
|
+
* @param options - Text content or object with content, embeds, and/or reply options (ping, replyTo)
|
|
323
323
|
* @example
|
|
324
324
|
* await message.reply('Pong!');
|
|
325
325
|
* await message.reply({ embeds: [embed] });
|
|
326
|
+
* await message.reply('No ping!', { ping: false });
|
|
327
|
+
* await message.reply({ content: 'Reply to other', replyTo: otherMessage });
|
|
326
328
|
*/
|
|
327
|
-
async reply(options) {
|
|
329
|
+
async reply(options, replyOptions) {
|
|
328
330
|
const opts = typeof options === "string" ? { content: options } : options;
|
|
329
|
-
const
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
331
|
+
const mergedReply = replyOptions ?? (opts.ping !== void 0 || opts.replyTo !== void 0) ? { ping: opts.ping, replyTo: opts.replyTo } : void 0;
|
|
332
|
+
const refMessage = mergedReply?.replyTo ?? this;
|
|
333
|
+
const ref = refMessage instanceof _Message ? { channel_id: refMessage.channelId, message_id: refMessage.id, guild_id: refMessage.guildId ?? void 0 } : { channel_id: refMessage.channelId, message_id: refMessage.messageId, guild_id: void 0 };
|
|
334
|
+
const payload = await _Message._createMessageBody(opts, ref, mergedReply?.ping !== false);
|
|
335
|
+
return this._send(payload);
|
|
336
|
+
}
|
|
337
|
+
/** Exposed for testing purposes, use Message.reply() or send() for normal use */
|
|
338
|
+
static async _createMessageBody(content, referenced_message, ping) {
|
|
339
|
+
if (typeof content === "string") {
|
|
340
|
+
if (content.length === 0) {
|
|
341
|
+
throw new RangeError("Cannot send an empty message");
|
|
336
342
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const
|
|
340
|
-
const
|
|
343
|
+
content = { content };
|
|
344
|
+
}
|
|
345
|
+
const base = buildSendBody(content);
|
|
346
|
+
const files = content.files?.length ? await resolveMessageFiles(content.files) : void 0;
|
|
347
|
+
const body = { ...base };
|
|
348
|
+
if (referenced_message) {
|
|
349
|
+
body.message_reference = referenced_message;
|
|
350
|
+
if (ping === false) {
|
|
351
|
+
body.flags = (body.flags ?? 0) | MessageFlags.SuppressNotifications;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return { files, body };
|
|
355
|
+
}
|
|
356
|
+
async _send(payload) {
|
|
357
|
+
const data = await this.client.rest.post(
|
|
358
|
+
Routes.channelMessages(this.channelId),
|
|
359
|
+
payload
|
|
360
|
+
);
|
|
361
|
+
this.client._addMessageToCache(this.channelId, data);
|
|
341
362
|
return new _Message(this.client, data);
|
|
342
363
|
}
|
|
343
364
|
/**
|
|
@@ -474,8 +495,18 @@ var MessageManager = class {
|
|
|
474
495
|
this.client = client;
|
|
475
496
|
this.channelId = channelId;
|
|
476
497
|
}
|
|
498
|
+
/**
|
|
499
|
+
* Get a message from cache. Returns undefined if not cached or caching is disabled.
|
|
500
|
+
* Requires options.cache.messages > 0.
|
|
501
|
+
* @param messageId - Snowflake of the message
|
|
502
|
+
*/
|
|
503
|
+
get(messageId) {
|
|
504
|
+
const data = this.client._getMessageCache(this.channelId)?.get(messageId);
|
|
505
|
+
return data ? new Message(this.client, data) : void 0;
|
|
506
|
+
}
|
|
477
507
|
/**
|
|
478
508
|
* Fetch a message by ID from this channel.
|
|
509
|
+
* When message caching is enabled, the fetched message is added to the cache.
|
|
479
510
|
* @param messageId - Snowflake of the message
|
|
480
511
|
* @returns The message
|
|
481
512
|
* @throws FluxerError with MESSAGE_NOT_FOUND if the message does not exist
|
|
@@ -485,6 +516,7 @@ var MessageManager = class {
|
|
|
485
516
|
const data = await this.client.rest.get(
|
|
486
517
|
Routes2.channelMessage(this.channelId, messageId)
|
|
487
518
|
);
|
|
519
|
+
this.client._addMessageToCache(this.channelId, data);
|
|
488
520
|
return new Message(this.client, data);
|
|
489
521
|
} catch (err) {
|
|
490
522
|
if (err instanceof RateLimitError) throw err;
|
|
@@ -553,6 +585,7 @@ var MessageCollector = class extends EventEmitter2 {
|
|
|
553
585
|
|
|
554
586
|
// src/structures/Channel.ts
|
|
555
587
|
import { ChannelType, Routes as Routes5 } from "@fluxerjs/types";
|
|
588
|
+
import { PermissionFlags } from "@fluxerjs/util";
|
|
556
589
|
import { emitDeprecationWarning } from "@fluxerjs/util";
|
|
557
590
|
|
|
558
591
|
// src/structures/Webhook.ts
|
|
@@ -688,7 +721,7 @@ var Webhook = class _Webhook extends Base {
|
|
|
688
721
|
);
|
|
689
722
|
}
|
|
690
723
|
const opts = typeof options === "string" ? { content: options } : options;
|
|
691
|
-
const body = buildSendBody(
|
|
724
|
+
const body = buildSendBody(opts);
|
|
692
725
|
if (opts.username !== void 0) body.username = opts.username;
|
|
693
726
|
if (opts.avatar_url !== void 0) body.avatar_url = opts.avatar_url;
|
|
694
727
|
if (opts.tts !== void 0) body.tts = opts.tts;
|
|
@@ -789,7 +822,7 @@ var Invite = class extends Base {
|
|
|
789
822
|
// src/structures/Channel.ts
|
|
790
823
|
var Channel = class _Channel extends Base {
|
|
791
824
|
/** Whether this channel has a send method (TextChannel, DMChannel). */
|
|
792
|
-
|
|
825
|
+
isTextBased() {
|
|
793
826
|
return "send" in this;
|
|
794
827
|
}
|
|
795
828
|
/** Whether this channel is a DM or Group DM. */
|
|
@@ -800,6 +833,9 @@ var Channel = class _Channel extends Base {
|
|
|
800
833
|
isVoice() {
|
|
801
834
|
return "bitrate" in this;
|
|
802
835
|
}
|
|
836
|
+
isLink() {
|
|
837
|
+
return "url" in this;
|
|
838
|
+
}
|
|
803
839
|
/** Create a DM channel from API data (type DM or GroupDM). */
|
|
804
840
|
static createDM(client, data) {
|
|
805
841
|
return new DMChannel(client, data);
|
|
@@ -863,6 +899,15 @@ var Channel = class _Channel extends Base {
|
|
|
863
899
|
async sendTyping() {
|
|
864
900
|
await this.client.rest.post(Routes5.channelTyping(this.id), { auth: true });
|
|
865
901
|
}
|
|
902
|
+
/**
|
|
903
|
+
* Whether the bot can send messages in this channel.
|
|
904
|
+
* For DMs: always true (when the channel exists).
|
|
905
|
+
* For guild channels: checks ViewChannel and SendMessages permissions via guild.members.me.
|
|
906
|
+
*/
|
|
907
|
+
canSendMessage() {
|
|
908
|
+
if (this.isDM()) return true;
|
|
909
|
+
return false;
|
|
910
|
+
}
|
|
866
911
|
};
|
|
867
912
|
var GuildChannel = class extends Channel {
|
|
868
913
|
guildId;
|
|
@@ -946,6 +991,32 @@ var GuildChannel = class extends Channel {
|
|
|
946
991
|
if (idx >= 0) this.permissionOverwrites[idx] = entry;
|
|
947
992
|
else this.permissionOverwrites.push(entry);
|
|
948
993
|
}
|
|
994
|
+
/**
|
|
995
|
+
* Whether the bot can send messages in this channel.
|
|
996
|
+
* Checks ViewChannel and SendMessages via guild.members.me permissions.
|
|
997
|
+
* Returns false if guild or bot member not cached.
|
|
998
|
+
*/
|
|
999
|
+
canSendMessage() {
|
|
1000
|
+
const guild = this.client.guilds.get(this.guildId);
|
|
1001
|
+
if (!guild) return false;
|
|
1002
|
+
const me = guild.members.me;
|
|
1003
|
+
if (!me) return false;
|
|
1004
|
+
const perms = me.permissionsIn(this);
|
|
1005
|
+
return perms.has(PermissionFlags.ViewChannel) && perms.has(PermissionFlags.SendMessages);
|
|
1006
|
+
}
|
|
1007
|
+
/**
|
|
1008
|
+
* Send a message to this guild channel.
|
|
1009
|
+
* Works for text and announcement channels. Voice/category/link channels will fail at the API.
|
|
1010
|
+
*/
|
|
1011
|
+
async send(options) {
|
|
1012
|
+
const opts = typeof options === "string" ? { content: options } : options;
|
|
1013
|
+
const body = buildSendBody(options);
|
|
1014
|
+
const files = opts.files?.length ? await resolveMessageFiles(opts.files) : void 0;
|
|
1015
|
+
const postOptions = files?.length ? { body, files } : { body };
|
|
1016
|
+
const data = await this.client.rest.post(Routes5.channelMessages(this.id), postOptions);
|
|
1017
|
+
this.client._addMessageToCache(this.id, data);
|
|
1018
|
+
return new Message(this.client, data);
|
|
1019
|
+
}
|
|
949
1020
|
/**
|
|
950
1021
|
* Remove a permission overwrite. DELETE /channels/{id}/permissions/{overwriteId}.
|
|
951
1022
|
*/
|
|
@@ -1009,6 +1080,7 @@ var TextChannel = class extends GuildChannel {
|
|
|
1009
1080
|
const files = opts.files?.length ? await resolveMessageFiles(opts.files) : void 0;
|
|
1010
1081
|
const postOptions = files?.length ? { body, files } : { body };
|
|
1011
1082
|
const data = await this.client.rest.post(Routes5.channelMessages(this.id), postOptions);
|
|
1083
|
+
this.client._addMessageToCache(this.id, data);
|
|
1012
1084
|
return new Message(this.client, data);
|
|
1013
1085
|
}
|
|
1014
1086
|
/** Message manager for this channel. Use channel.messages.fetch(messageId). */
|
|
@@ -1100,6 +1172,7 @@ var DMChannel = class extends Channel {
|
|
|
1100
1172
|
const files = opts.files?.length ? await resolveMessageFiles(opts.files) : void 0;
|
|
1101
1173
|
const postOptions = files?.length ? { body, files } : { body };
|
|
1102
1174
|
const data = await this.client.rest.post(Routes5.channelMessages(this.id), postOptions);
|
|
1175
|
+
this.client._addMessageToCache(this.id, data);
|
|
1103
1176
|
return new Message(this.client, data);
|
|
1104
1177
|
}
|
|
1105
1178
|
/** Message manager for this channel. Use channel.messages.fetch(messageId). */
|
|
@@ -1183,7 +1256,7 @@ var ChannelManager = class extends Collection4 {
|
|
|
1183
1256
|
* @throws FluxerError with CHANNEL_NOT_FOUND if the channel does not exist
|
|
1184
1257
|
* @example
|
|
1185
1258
|
* const channel = await client.channels.resolve(message.channelId);
|
|
1186
|
-
* if (channel?.
|
|
1259
|
+
* if (channel?.isTextBased()) await channel.send('Hello!');
|
|
1187
1260
|
*/
|
|
1188
1261
|
async resolve(channelId) {
|
|
1189
1262
|
return this.get(channelId) ?? this.fetch(channelId);
|
|
@@ -1195,7 +1268,7 @@ var ChannelManager = class extends Collection4 {
|
|
|
1195
1268
|
* @throws FluxerError with CHANNEL_NOT_FOUND if the channel does not exist
|
|
1196
1269
|
* @example
|
|
1197
1270
|
* const channel = await client.channels.fetch(channelId);
|
|
1198
|
-
* if (channel?.
|
|
1271
|
+
* if (channel?.isTextBased()) await channel.send('Hello!');
|
|
1199
1272
|
*/
|
|
1200
1273
|
async fetch(channelId) {
|
|
1201
1274
|
const cached = this.get(channelId);
|
|
@@ -1274,6 +1347,7 @@ var ChannelManager = class extends Collection4 {
|
|
|
1274
1347
|
const files = opts.files?.length ? await resolveMessageFiles(opts.files) : void 0;
|
|
1275
1348
|
const postOptions = files?.length ? { body, files } : { body };
|
|
1276
1349
|
const data = await this.client.rest.post(Routes6.channelMessages(channelId), postOptions);
|
|
1350
|
+
this.client._addMessageToCache(channelId, data);
|
|
1277
1351
|
return new Message(this.client, data);
|
|
1278
1352
|
}
|
|
1279
1353
|
};
|
|
@@ -1295,12 +1369,12 @@ import { Collection as Collection6 } from "@fluxerjs/collection";
|
|
|
1295
1369
|
import { Routes as Routes9 } from "@fluxerjs/types";
|
|
1296
1370
|
|
|
1297
1371
|
// src/structures/GuildMember.ts
|
|
1298
|
-
import {
|
|
1372
|
+
import { BitField } from "@fluxerjs/util";
|
|
1299
1373
|
import { Routes as Routes8 } from "@fluxerjs/types";
|
|
1300
1374
|
|
|
1301
1375
|
// src/util/permissions.ts
|
|
1302
1376
|
import { OverwriteType } from "@fluxerjs/types";
|
|
1303
|
-
import { ALL_PERMISSIONS_BIGINT } from "@fluxerjs/util";
|
|
1377
|
+
import { ALL_PERMISSIONS_BIGINT, PermissionFlags as PermissionFlags2 } from "@fluxerjs/util";
|
|
1304
1378
|
function computePermissions(basePermissions, overwrites, memberRoles, memberId, isOwner) {
|
|
1305
1379
|
if (isOwner) return ALL_PERMISSIONS_BIGINT;
|
|
1306
1380
|
let perms = basePermissions;
|
|
@@ -1311,12 +1385,7 @@ function computePermissions(basePermissions, overwrites, memberRoles, memberId,
|
|
|
1311
1385
|
const deny = BigInt(overwrite.deny || "0");
|
|
1312
1386
|
perms = perms & ~deny | allow;
|
|
1313
1387
|
}
|
|
1314
|
-
return perms;
|
|
1315
|
-
}
|
|
1316
|
-
function hasPermission(bitfield, permission) {
|
|
1317
|
-
const Administrator = 1n << 3n;
|
|
1318
|
-
if ((bitfield & Administrator) !== 0n) return true;
|
|
1319
|
-
return (bitfield & permission) === permission;
|
|
1388
|
+
return (perms & PermissionFlags2.Administrator) !== 0n ? ALL_PERMISSIONS_BIGINT : perms;
|
|
1320
1389
|
}
|
|
1321
1390
|
|
|
1322
1391
|
// src/structures/GuildMemberRoleManager.ts
|
|
@@ -1518,13 +1587,7 @@ var GuildMember = class extends Base {
|
|
|
1518
1587
|
const ownerId = this.guild.ownerId;
|
|
1519
1588
|
const isOwner = ownerId != null && ownerId !== "" && String(ownerId) === String(this.id);
|
|
1520
1589
|
const perms = computePermissions(base, [], [], this.id, isOwner);
|
|
1521
|
-
return
|
|
1522
|
-
has(permission) {
|
|
1523
|
-
const perm = typeof permission === "number" ? permission : PermissionFlagsMap[String(permission)];
|
|
1524
|
-
if (perm === void 0) return false;
|
|
1525
|
-
return hasPermission(perms, BigInt(perm));
|
|
1526
|
-
}
|
|
1527
|
-
};
|
|
1590
|
+
return new BitField(perms);
|
|
1528
1591
|
}
|
|
1529
1592
|
/**
|
|
1530
1593
|
* Compute the member's effective permissions in a guild channel.
|
|
@@ -1546,22 +1609,16 @@ var GuildMember = class extends Base {
|
|
|
1546
1609
|
this.id,
|
|
1547
1610
|
isOwner
|
|
1548
1611
|
);
|
|
1549
|
-
return
|
|
1550
|
-
has(permission) {
|
|
1551
|
-
const perm = typeof permission === "number" ? permission : PermissionFlagsMap[String(permission)];
|
|
1552
|
-
if (perm === void 0) return false;
|
|
1553
|
-
return hasPermission(perms, BigInt(perm));
|
|
1554
|
-
}
|
|
1555
|
-
};
|
|
1612
|
+
return new BitField(perms);
|
|
1556
1613
|
}
|
|
1557
1614
|
_computeBasePermissions() {
|
|
1558
1615
|
let base = 0n;
|
|
1559
1616
|
const everyone = this.guild.roles.get(this.guild.id);
|
|
1560
|
-
if (everyone) base |=
|
|
1617
|
+
if (everyone) base |= everyone.permissions.bitfield;
|
|
1561
1618
|
for (const roleId of this.roles.roleIds) {
|
|
1562
1619
|
if (roleId === this.guild.id) continue;
|
|
1563
1620
|
const role = this.guild.roles.get(roleId);
|
|
1564
|
-
if (role) base |=
|
|
1621
|
+
if (role) base |= role.permissions.bitfield;
|
|
1565
1622
|
}
|
|
1566
1623
|
return base;
|
|
1567
1624
|
}
|
|
@@ -1646,8 +1703,10 @@ var GuildMemberManager = class extends Collection6 {
|
|
|
1646
1703
|
// src/structures/Role.ts
|
|
1647
1704
|
import { Routes as Routes10 } from "@fluxerjs/types";
|
|
1648
1705
|
import {
|
|
1649
|
-
PermissionFlags,
|
|
1650
|
-
resolvePermissionsToBitfield
|
|
1706
|
+
PermissionFlags as PermissionFlags4,
|
|
1707
|
+
resolvePermissionsToBitfield,
|
|
1708
|
+
ALL_PERMISSIONS_BIGINT as ALL_PERMISSIONS_BIGINT2,
|
|
1709
|
+
PermissionsBitField
|
|
1651
1710
|
} from "@fluxerjs/util";
|
|
1652
1711
|
var Role = class extends Base {
|
|
1653
1712
|
client;
|
|
@@ -1656,7 +1715,7 @@ var Role = class extends Base {
|
|
|
1656
1715
|
name;
|
|
1657
1716
|
color;
|
|
1658
1717
|
position;
|
|
1659
|
-
|
|
1718
|
+
_permissions;
|
|
1660
1719
|
hoist;
|
|
1661
1720
|
mentionable;
|
|
1662
1721
|
unicodeEmoji;
|
|
@@ -1673,18 +1732,24 @@ var Role = class extends Base {
|
|
|
1673
1732
|
this.name = data.name;
|
|
1674
1733
|
this.color = data.color;
|
|
1675
1734
|
this.position = data.position;
|
|
1676
|
-
this.
|
|
1735
|
+
this._permissions = data.permissions;
|
|
1677
1736
|
this.hoist = !!data.hoist;
|
|
1678
1737
|
this.mentionable = !!data.mentionable;
|
|
1679
1738
|
this.unicodeEmoji = data.unicode_emoji ?? null;
|
|
1680
1739
|
this.hoistPosition = data.hoist_position ?? null;
|
|
1681
1740
|
}
|
|
1741
|
+
get permissions() {
|
|
1742
|
+
const bits = BigInt(this._permissions);
|
|
1743
|
+
return new PermissionsBitField(
|
|
1744
|
+
(bits & PermissionFlags4.Administrator) !== 0n ? ALL_PERMISSIONS_BIGINT2 : bits
|
|
1745
|
+
);
|
|
1746
|
+
}
|
|
1682
1747
|
/** Update mutable fields from fresh API data. Used by edit and gateway events. */
|
|
1683
1748
|
_patch(data) {
|
|
1684
1749
|
if (data.name !== void 0) this.name = data.name;
|
|
1685
1750
|
if (data.color !== void 0) this.color = data.color;
|
|
1686
1751
|
if (data.position !== void 0) this.position = data.position;
|
|
1687
|
-
if (data.permissions !== void 0) this.
|
|
1752
|
+
if (data.permissions !== void 0) this._permissions = data.permissions;
|
|
1688
1753
|
if (data.hoist !== void 0) this.hoist = !!data.hoist;
|
|
1689
1754
|
if (data.mentionable !== void 0) this.mentionable = !!data.mentionable;
|
|
1690
1755
|
if (data.unicode_emoji !== void 0) this.unicodeEmoji = data.unicode_emoji ?? null;
|
|
@@ -1694,24 +1759,6 @@ var Role = class extends Base {
|
|
|
1694
1759
|
toString() {
|
|
1695
1760
|
return `<@&${this.id}>`;
|
|
1696
1761
|
}
|
|
1697
|
-
/**
|
|
1698
|
-
* Check if this role has a permission. Administrator grants all permissions.
|
|
1699
|
-
* @param permission - Permission flag, name, or resolvable
|
|
1700
|
-
* @returns true if the role has the permission
|
|
1701
|
-
* @example
|
|
1702
|
-
* if (role.has(PermissionFlags.BanMembers)) { ... }
|
|
1703
|
-
* if (role.has('ManageChannels')) { ... }
|
|
1704
|
-
*/
|
|
1705
|
-
has(permission) {
|
|
1706
|
-
const perm = typeof permission === "number" ? permission : PermissionFlags[permission];
|
|
1707
|
-
if (perm === void 0) return false;
|
|
1708
|
-
const permNum = Number(perm);
|
|
1709
|
-
const rolePerms = BigInt(this.permissions);
|
|
1710
|
-
const permBig = BigInt(permNum);
|
|
1711
|
-
if (permBig < 0) return false;
|
|
1712
|
-
if ((rolePerms & BigInt(PermissionFlags.Administrator)) !== 0n) return true;
|
|
1713
|
-
return (rolePerms & permBig) === permBig;
|
|
1714
|
-
}
|
|
1715
1762
|
/**
|
|
1716
1763
|
* Edit this role.
|
|
1717
1764
|
* Requires Manage Roles permission.
|
|
@@ -2756,13 +2803,28 @@ handlers.set("MESSAGE_CREATE", async (client, d) => {
|
|
|
2756
2803
|
guild.members.set(member.id, member);
|
|
2757
2804
|
}
|
|
2758
2805
|
}
|
|
2806
|
+
client._addMessageToCache(data.channel_id, data);
|
|
2759
2807
|
client.emit(Events.MessageCreate, new Message(client, data));
|
|
2760
2808
|
});
|
|
2761
2809
|
handlers.set("MESSAGE_UPDATE", async (client, d) => {
|
|
2762
|
-
|
|
2810
|
+
const partial = d;
|
|
2811
|
+
const cache = client._getMessageCache(partial.channel_id);
|
|
2812
|
+
let oldMessage = null;
|
|
2813
|
+
let mergedData = partial;
|
|
2814
|
+
if (cache) {
|
|
2815
|
+
const oldData = cache.get(partial.id);
|
|
2816
|
+
if (oldData) {
|
|
2817
|
+
oldMessage = new Message(client, oldData);
|
|
2818
|
+
mergedData = { ...oldData, ...partial };
|
|
2819
|
+
}
|
|
2820
|
+
cache.set(partial.id, mergedData);
|
|
2821
|
+
}
|
|
2822
|
+
const newMessage = new Message(client, mergedData);
|
|
2823
|
+
client.emit(Events.MessageUpdate, oldMessage, newMessage);
|
|
2763
2824
|
});
|
|
2764
2825
|
handlers.set("MESSAGE_DELETE", async (client, d) => {
|
|
2765
2826
|
const data = d;
|
|
2827
|
+
client._removeMessageFromCache(data.channel_id, data.id);
|
|
2766
2828
|
const channel = client.channels.get(data.channel_id) ?? null;
|
|
2767
2829
|
client.emit(Events.MessageDelete, {
|
|
2768
2830
|
id: data.id,
|
|
@@ -2825,6 +2887,7 @@ handlers.set("GUILD_CREATE", async (client, d) => {
|
|
|
2825
2887
|
if (g.voice_states?.length) {
|
|
2826
2888
|
client.emit(Events.VoiceStatesSync, { guildId: guild.id, voiceStates: g.voice_states });
|
|
2827
2889
|
}
|
|
2890
|
+
client._onGuildReceived(guild.id);
|
|
2828
2891
|
});
|
|
2829
2892
|
handlers.set("GUILD_UPDATE", async (client, d) => {
|
|
2830
2893
|
const guildData = normalizeGuildPayload(d);
|
|
@@ -2931,7 +2994,11 @@ handlers.set("VOICE_SERVER_UPDATE", async (client, d) => {
|
|
|
2931
2994
|
client.emit(Events.VoiceServerUpdate, d);
|
|
2932
2995
|
});
|
|
2933
2996
|
handlers.set("MESSAGE_DELETE_BULK", async (client, d) => {
|
|
2934
|
-
|
|
2997
|
+
const data = d;
|
|
2998
|
+
for (const id of data.ids ?? []) {
|
|
2999
|
+
client._removeMessageFromCache(data.channel_id, id);
|
|
3000
|
+
}
|
|
3001
|
+
client.emit(Events.MessageDeleteBulk, data);
|
|
2935
3002
|
});
|
|
2936
3003
|
handlers.set("GUILD_BAN_ADD", async (client, d) => {
|
|
2937
3004
|
const data = d;
|
|
@@ -2957,7 +3024,11 @@ handlers.set("GUILD_EMOJIS_UPDATE", async (client, d) => {
|
|
|
2957
3024
|
if (!e.id || e.name == null) continue;
|
|
2958
3025
|
guild.emojis.set(
|
|
2959
3026
|
e.id,
|
|
2960
|
-
new GuildEmoji(
|
|
3027
|
+
new GuildEmoji(
|
|
3028
|
+
client,
|
|
3029
|
+
{ id: e.id, name: e.name, animated: e.animated ?? false, guild_id: guild.id },
|
|
3030
|
+
guild.id
|
|
3031
|
+
)
|
|
2961
3032
|
);
|
|
2962
3033
|
}
|
|
2963
3034
|
}
|
|
@@ -3083,6 +3154,10 @@ var Client = class extends EventEmitter3 {
|
|
|
3083
3154
|
/** Timestamp when the client became ready. Null until READY is received. */
|
|
3084
3155
|
readyAt = null;
|
|
3085
3156
|
_ws = null;
|
|
3157
|
+
/** When waitForGuilds, set of guild IDs we're waiting for GUILD_CREATE on. Null when not waiting. */
|
|
3158
|
+
_pendingGuildIds = null;
|
|
3159
|
+
/** Per-channel message cache (channelId -> messageId -> APIMessage). Used when options.cache.messages > 0. */
|
|
3160
|
+
_messageCaches = null;
|
|
3086
3161
|
/**
|
|
3087
3162
|
* Resolve an emoji argument to the API format (unicode or "name:id").
|
|
3088
3163
|
* Supports: <:name:id>, :name:, name:id, { name, id }, unicode.
|
|
@@ -3171,10 +3246,52 @@ var Client = class extends EventEmitter3 {
|
|
|
3171
3246
|
/**
|
|
3172
3247
|
* Send a message to any channel by ID. Shorthand for client.channels.send().
|
|
3173
3248
|
* Works even when the channel is not cached.
|
|
3249
|
+
* @deprecated Use client.channels.send(channelId, payload).
|
|
3174
3250
|
*/
|
|
3175
3251
|
async sendToChannel(channelId, payload) {
|
|
3252
|
+
emitDeprecationWarning3(
|
|
3253
|
+
"Client.sendToChannel()",
|
|
3254
|
+
"Use client.channels.send(channelId, payload)."
|
|
3255
|
+
);
|
|
3176
3256
|
return this.channels.send(channelId, payload);
|
|
3177
3257
|
}
|
|
3258
|
+
/**
|
|
3259
|
+
* Get the message cache for a channel. Returns null if message caching is disabled.
|
|
3260
|
+
* Used by MessageManager.get() and event handlers.
|
|
3261
|
+
* @internal
|
|
3262
|
+
*/
|
|
3263
|
+
_getMessageCache(channelId) {
|
|
3264
|
+
const limit = this.options.cache?.messages ?? 0;
|
|
3265
|
+
if (limit <= 0) return null;
|
|
3266
|
+
if (!this._messageCaches) this._messageCaches = /* @__PURE__ */ new Map();
|
|
3267
|
+
let cache = this._messageCaches.get(channelId);
|
|
3268
|
+
if (!cache) {
|
|
3269
|
+
cache = /* @__PURE__ */ new Map();
|
|
3270
|
+
this._messageCaches.set(channelId, cache);
|
|
3271
|
+
}
|
|
3272
|
+
return cache;
|
|
3273
|
+
}
|
|
3274
|
+
/**
|
|
3275
|
+
* Add a message to the channel cache. Evicts oldest (FIFO) when over limit.
|
|
3276
|
+
* @internal
|
|
3277
|
+
*/
|
|
3278
|
+
_addMessageToCache(channelId, data) {
|
|
3279
|
+
const cache = this._getMessageCache(channelId);
|
|
3280
|
+
if (!cache) return;
|
|
3281
|
+
const limit = this.options.cache?.messages ?? 0;
|
|
3282
|
+
if (limit > 0 && cache.size >= limit && !cache.has(data.id)) {
|
|
3283
|
+
const firstKey = cache.keys().next().value;
|
|
3284
|
+
if (firstKey !== void 0) cache.delete(firstKey);
|
|
3285
|
+
}
|
|
3286
|
+
cache.set(data.id, { ...data });
|
|
3287
|
+
}
|
|
3288
|
+
/**
|
|
3289
|
+
* Remove a message from the channel cache.
|
|
3290
|
+
* @internal
|
|
3291
|
+
*/
|
|
3292
|
+
_removeMessageFromCache(channelId, messageId) {
|
|
3293
|
+
this._messageCaches?.get(channelId)?.delete(messageId);
|
|
3294
|
+
}
|
|
3178
3295
|
/**
|
|
3179
3296
|
* Get or create a User from API data. Caches in client.users.
|
|
3180
3297
|
* Updates existing user's username, avatar, etc. when fresh data is provided.
|
|
@@ -3255,7 +3372,13 @@ var Client = class extends EventEmitter3 {
|
|
|
3255
3372
|
data
|
|
3256
3373
|
}) => {
|
|
3257
3374
|
this.user = new ClientUser(this, data.user);
|
|
3375
|
+
const waitForGuilds = this.options.waitForGuilds === true;
|
|
3376
|
+
const pending = waitForGuilds ? /* @__PURE__ */ new Set() : null;
|
|
3258
3377
|
for (const g of data.guilds ?? []) {
|
|
3378
|
+
if (g.unavailable === true) {
|
|
3379
|
+
if (pending !== null && g.id) pending.add(g.id);
|
|
3380
|
+
continue;
|
|
3381
|
+
}
|
|
3259
3382
|
const guildData = normalizeGuildPayload(g);
|
|
3260
3383
|
if (!guildData) continue;
|
|
3261
3384
|
const guild = new Guild(this, guildData);
|
|
@@ -3275,8 +3398,11 @@ var Client = class extends EventEmitter3 {
|
|
|
3275
3398
|
});
|
|
3276
3399
|
}
|
|
3277
3400
|
}
|
|
3278
|
-
|
|
3279
|
-
|
|
3401
|
+
if (pending !== null && pending.size > 0) {
|
|
3402
|
+
this._pendingGuildIds = pending;
|
|
3403
|
+
return;
|
|
3404
|
+
}
|
|
3405
|
+
this._finalizeReady();
|
|
3280
3406
|
}
|
|
3281
3407
|
);
|
|
3282
3408
|
this._ws.on("error", ({ error }) => this.emit(Events.Error, error));
|
|
@@ -3284,6 +3410,25 @@ var Client = class extends EventEmitter3 {
|
|
|
3284
3410
|
await this._ws.connect();
|
|
3285
3411
|
return token;
|
|
3286
3412
|
}
|
|
3413
|
+
/**
|
|
3414
|
+
* Called when all guilds have been received (or immediately if not waiting).
|
|
3415
|
+
* Sets readyAt, emits Ready, clears pending state.
|
|
3416
|
+
*/
|
|
3417
|
+
_finalizeReady() {
|
|
3418
|
+
this._pendingGuildIds = null;
|
|
3419
|
+
this.readyAt = /* @__PURE__ */ new Date();
|
|
3420
|
+
this.emit(Events.Ready);
|
|
3421
|
+
}
|
|
3422
|
+
/**
|
|
3423
|
+
* Called by GUILD_CREATE handler when waitForGuilds is enabled.
|
|
3424
|
+
* Removes guild from pending set; when empty, finalizes ready.
|
|
3425
|
+
*/
|
|
3426
|
+
_onGuildReceived(guildId) {
|
|
3427
|
+
const pending = this._pendingGuildIds;
|
|
3428
|
+
if (pending === null) return;
|
|
3429
|
+
pending.delete(guildId);
|
|
3430
|
+
if (pending.size === 0) this._finalizeReady();
|
|
3431
|
+
}
|
|
3287
3432
|
/** Disconnect from the gateway and clear cached data. */
|
|
3288
3433
|
async destroy() {
|
|
3289
3434
|
if (this._ws) {
|
|
@@ -3293,6 +3438,7 @@ var Client = class extends EventEmitter3 {
|
|
|
3293
3438
|
this.rest.setToken(null);
|
|
3294
3439
|
this.user = null;
|
|
3295
3440
|
this.readyAt = null;
|
|
3441
|
+
this._pendingGuildIds = null;
|
|
3296
3442
|
this.guilds.clear();
|
|
3297
3443
|
this.channels.clear();
|
|
3298
3444
|
this.users.clear();
|
|
@@ -3325,8 +3471,8 @@ import { EmbedBuilder as EmbedBuilder3, MessagePayload, AttachmentBuilder } from
|
|
|
3325
3471
|
import { Routes as Routes21, GatewayOpcodes, MessageAttachmentFlags } from "@fluxerjs/types";
|
|
3326
3472
|
import { resolveTenorToImageUrl, parseUserMention, parsePrefixCommand } from "@fluxerjs/util";
|
|
3327
3473
|
import {
|
|
3328
|
-
PermissionsBitField,
|
|
3329
|
-
PermissionFlags as
|
|
3474
|
+
PermissionsBitField as PermissionsBitField2,
|
|
3475
|
+
PermissionFlags as PermissionFlags5,
|
|
3330
3476
|
resolvePermissionsToBitfield as resolvePermissionsToBitfield3,
|
|
3331
3477
|
UserFlagsBitField,
|
|
3332
3478
|
UserFlagsBits
|
|
@@ -3362,8 +3508,8 @@ export {
|
|
|
3362
3508
|
MessageManager,
|
|
3363
3509
|
MessagePayload,
|
|
3364
3510
|
MessageReaction,
|
|
3365
|
-
|
|
3366
|
-
PermissionsBitField,
|
|
3511
|
+
PermissionFlags5 as PermissionFlags,
|
|
3512
|
+
PermissionsBitField2 as PermissionsBitField,
|
|
3367
3513
|
ReactionCollector,
|
|
3368
3514
|
Role,
|
|
3369
3515
|
Routes21 as Routes,
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.2.
|
|
6
|
+
"version": "1.2.3",
|
|
7
7
|
"description": "A fully-featured SDK for Fluxer bots",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
"dist"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@fluxerjs/
|
|
38
|
-
"@fluxerjs/
|
|
39
|
-
"@fluxerjs/
|
|
40
|
-
"@fluxerjs/
|
|
41
|
-
"@fluxerjs/
|
|
42
|
-
"@fluxerjs/
|
|
37
|
+
"@fluxerjs/types": "1.2.3",
|
|
38
|
+
"@fluxerjs/rest": "1.2.3",
|
|
39
|
+
"@fluxerjs/collection": "1.2.3",
|
|
40
|
+
"@fluxerjs/builders": "1.2.3",
|
|
41
|
+
"@fluxerjs/ws": "1.2.3",
|
|
42
|
+
"@fluxerjs/util": "1.2.3"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/node": "^20.0.0",
|
|
@@ -55,6 +55,6 @@
|
|
|
55
55
|
"lint": "eslint src --max-warnings 0 --config ../../eslint.config.js",
|
|
56
56
|
"lint:fix": "eslint src --fix --config ../../eslint.config.js",
|
|
57
57
|
"test": "vitest run --passWithNoTests",
|
|
58
|
-
"test:coverage": "vitest run --coverage
|
|
58
|
+
"test:coverage": "vitest run --coverage"
|
|
59
59
|
}
|
|
60
60
|
}
|