@fluxerjs/core 1.0.7 → 1.0.8

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.
Files changed (113) hide show
  1. package/dist/{Channel-OSOB6ELO.mjs → Channel-TWPDKW2P.mjs} +1 -1
  2. package/dist/{ClientUser-RNDKHQ3Z.mjs → ClientUser-2K2BACK7.mjs} +1 -2
  3. package/dist/{Guild-GOQZ7XP4.mjs → Guild-CMZGA6DW.mjs} +3 -1
  4. package/dist/{GuildMember-BJJNCL6W.mjs → GuildMember-DW2N6ITI.mjs} +1 -2
  5. package/dist/{Message-QXPHQOVC.mjs → Message-G2QIKZQK.mjs} +1 -2
  6. package/dist/MessageReaction-XRPYZDSC.mjs +7 -0
  7. package/dist/{Webhook-AG6QFM2I.mjs → Role-SVLWIAMN.mjs} +3 -3
  8. package/dist/{Webhook-2RHBXH7R.mjs → Webhook-2MQESB7Z.mjs} +1 -1
  9. package/dist/{chunk-J3EIGOXQ.mjs → chunk-4GCZFOS5.mjs} +20 -6
  10. package/dist/{chunk-PO5JZQVN.mjs → chunk-CO5EL5LH.mjs} +71 -14
  11. package/dist/{chunk-WYSHH4LR.mjs → chunk-CZIO2D7F.mjs} +72 -6
  12. package/dist/chunk-HBF5QEDH.mjs +42 -0
  13. package/dist/{chunk-NISGA2YZ.mjs → chunk-JVEOQFUX.mjs} +1 -4
  14. package/dist/chunk-SQVCCSNN.mjs +41 -0
  15. package/dist/chunk-TJVZEILY.mjs +120 -0
  16. package/dist/{chunk-T2NSVWBH.mjs → chunk-ZGMM6IPQ.mjs} +3 -1
  17. package/dist/index.d.mts +374 -61
  18. package/dist/index.d.ts +374 -61
  19. package/dist/index.js +1001 -409
  20. package/dist/index.mjs +505 -192
  21. package/package.json +27 -8
  22. package/dist/Channel-2WNJ445K.mjs +0 -17
  23. package/dist/Channel-BEZOW4VC.mjs +0 -17
  24. package/dist/Channel-DPLLHL7Y.mjs +0 -19
  25. package/dist/Channel-HM2UY4DN.mjs +0 -17
  26. package/dist/Channel-IKL3SJXN.mjs +0 -17
  27. package/dist/Channel-KILNV5V3.mjs +0 -17
  28. package/dist/Channel-KOTARBSF.mjs +0 -17
  29. package/dist/Channel-ON7O3D3M.mjs +0 -17
  30. package/dist/Channel-TOAQGSRX.mjs +0 -17
  31. package/dist/Channel-VENHOL7S.mjs +0 -17
  32. package/dist/Channel-YVGPVOVB.mjs +0 -17
  33. package/dist/ClientUser-6HBAPU6H.mjs +0 -8
  34. package/dist/ClientUser-ALGC4FNY.mjs +0 -8
  35. package/dist/ClientUser-J6HQVSDJ.mjs +0 -9
  36. package/dist/ClientUser-LLL6WX35.mjs +0 -8
  37. package/dist/ClientUser-N7ZXYAQ3.mjs +0 -8
  38. package/dist/Guild-36EGAAEW.mjs +0 -8
  39. package/dist/Guild-5UBZNIGD.mjs +0 -9
  40. package/dist/Guild-CA3W6DOD.mjs +0 -8
  41. package/dist/Guild-GIXJJBFM.mjs +0 -9
  42. package/dist/Guild-NHNQ5TIA.mjs +0 -8
  43. package/dist/Guild-S436SLOP.mjs +0 -9
  44. package/dist/Guild-WAFXK2EX.mjs +0 -9
  45. package/dist/Guild-XPOMHZZG.mjs +0 -9
  46. package/dist/Guild-ZOFF5LFR.mjs +0 -8
  47. package/dist/GuildMember-FX2JAWES.mjs +0 -8
  48. package/dist/GuildMember-K5FLBNHV.mjs +0 -8
  49. package/dist/GuildMember-RGVPVUAG.mjs +0 -9
  50. package/dist/GuildMember-UBNHZBCO.mjs +0 -8
  51. package/dist/GuildMember-UU26WJGN.mjs +0 -8
  52. package/dist/GuildMember-XF7K2R45.mjs +0 -9
  53. package/dist/Message-23Z3RPCZ.mjs +0 -9
  54. package/dist/Message-33APPS76.mjs +0 -9
  55. package/dist/Message-6RSAGIRP.mjs +0 -8
  56. package/dist/Message-OXTQHFCF.mjs +0 -8
  57. package/dist/Message-PZUU7ZFR.mjs +0 -9
  58. package/dist/Message-R7GZYIQQ.mjs +0 -8
  59. package/dist/Message-W624MHJF.mjs +0 -8
  60. package/dist/Message-XB5WNMHL.mjs +0 -9
  61. package/dist/Message-ZCS7IGJX.mjs +0 -8
  62. package/dist/Webhook-NUQCJAWZ.mjs +0 -7
  63. package/dist/Webhook-TGAZZRQQ.mjs +0 -7
  64. package/dist/chunk-2FIZRRSO.mjs +0 -88
  65. package/dist/chunk-3CNUPFDI.mjs +0 -59
  66. package/dist/chunk-4DBGMFOQ.mjs +0 -14
  67. package/dist/chunk-5HQRX3KJ.mjs +0 -70
  68. package/dist/chunk-62S4AB2S.mjs +0 -54
  69. package/dist/chunk-6CEMF2LO.mjs +0 -14
  70. package/dist/chunk-6EBNOON4.mjs +0 -86
  71. package/dist/chunk-72OY7B3D.mjs +0 -72
  72. package/dist/chunk-7FYM4D2E.mjs +0 -50
  73. package/dist/chunk-7GZN6JXT.mjs +0 -50
  74. package/dist/chunk-7H3TKJUT.mjs +0 -53
  75. package/dist/chunk-7SIS5CUA.mjs +0 -14
  76. package/dist/chunk-BGJSL6JI.mjs +0 -14
  77. package/dist/chunk-BUEXP5SZ.mjs +0 -70
  78. package/dist/chunk-BYTAODAO.mjs +0 -70
  79. package/dist/chunk-CQ5ZVTLX.mjs +0 -71
  80. package/dist/chunk-DJBCSVZX.mjs +0 -102
  81. package/dist/chunk-DLROMCIJ.mjs +0 -50
  82. package/dist/chunk-DPZHAYCK.mjs +0 -71
  83. package/dist/chunk-E75ZVY3I.mjs +0 -14
  84. package/dist/chunk-EF32ILJL.mjs +0 -102
  85. package/dist/chunk-F2EEQP5O.mjs +0 -86
  86. package/dist/chunk-FK5X6HFL.mjs +0 -111
  87. package/dist/chunk-FNFID6QB.mjs +0 -45
  88. package/dist/chunk-G4L7WAJS.mjs +0 -64
  89. package/dist/chunk-GUNWHOQO.mjs +0 -42
  90. package/dist/chunk-IPHFDI2L.mjs +0 -68
  91. package/dist/chunk-JJHZBWZM.mjs +0 -118
  92. package/dist/chunk-L25ON7WB.mjs +0 -52
  93. package/dist/chunk-LBBIQOSH.mjs +0 -53
  94. package/dist/chunk-LVMFPATK.mjs +0 -54
  95. package/dist/chunk-NOLYW3V4.mjs +0 -140
  96. package/dist/chunk-OHIHIQAS.mjs +0 -102
  97. package/dist/chunk-P4IRDGB4.mjs +0 -43
  98. package/dist/chunk-PYYXC7US.mjs +0 -76
  99. package/dist/chunk-QDCFQF6J.mjs +0 -36
  100. package/dist/chunk-QDNFJVVE.mjs +0 -70
  101. package/dist/chunk-QXJNV5EJ.mjs +0 -110
  102. package/dist/chunk-RXHJYGSJ.mjs +0 -53
  103. package/dist/chunk-SW6KNICI.mjs +0 -52
  104. package/dist/chunk-TE5IC7IP.mjs +0 -36
  105. package/dist/chunk-TMDZALIN.mjs +0 -110
  106. package/dist/chunk-WFONGZGK.mjs +0 -42
  107. package/dist/chunk-WZVY7DA6.mjs +0 -44
  108. package/dist/chunk-XTDZQD4A.mjs +0 -110
  109. package/dist/chunk-XXCBJJZE.mjs +0 -88
  110. package/dist/chunk-YKP7JHV2.mjs +0 -102
  111. package/dist/chunk-YSKZR66G.mjs +0 -102
  112. package/dist/chunk-ZHRQQZ4X.mjs +0 -102
  113. package/dist/chunk-ZMIMAMO2.mjs +0 -14
package/dist/index.js CHANGED
@@ -20,6 +20,28 @@ var __copyProps = (to, from, except, desc) => {
20
20
  };
21
21
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
22
 
23
+ // src/client/MessageManager.ts
24
+ var MessageManager;
25
+ var init_MessageManager = __esm({
26
+ "src/client/MessageManager.ts"() {
27
+ "use strict";
28
+ MessageManager = class {
29
+ constructor(client, channelId) {
30
+ this.client = client;
31
+ this.channelId = channelId;
32
+ }
33
+ /**
34
+ * Fetch a message by ID from this channel.
35
+ * @param messageId - Snowflake of the message
36
+ * @returns The message, or null if not found
37
+ */
38
+ async fetch(messageId) {
39
+ return this.client.channels.fetchMessage(this.channelId, messageId);
40
+ }
41
+ };
42
+ }
43
+ });
44
+
23
45
  // src/structures/Base.ts
24
46
  var Base;
25
47
  var init_Base = __esm({
@@ -30,15 +52,6 @@ var init_Base = __esm({
30
52
  }
31
53
  });
32
54
 
33
- // src/util/Constants.ts
34
- var CDN_URL;
35
- var init_Constants = __esm({
36
- "src/util/Constants.ts"() {
37
- "use strict";
38
- CDN_URL = "https://fluxerusercontent.com";
39
- }
40
- });
41
-
42
55
  // src/structures/Webhook.ts
43
56
  var Webhook_exports = {};
44
57
  __export(Webhook_exports, {
@@ -80,7 +93,9 @@ var init_Webhook = __esm({
80
93
  */
81
94
  async send(options) {
82
95
  if (!this.token) {
83
- throw new Error("Webhook token is required to send. The token is only returned when creating a webhook; fetched webhooks cannot send.");
96
+ throw new Error(
97
+ "Webhook token is required to send. The token is only returned when creating a webhook; fetched webhooks cannot send."
98
+ );
84
99
  }
85
100
  const body = typeof options === "string" ? { content: options } : options;
86
101
  await this.client.rest.post(import_types.Routes.webhookExecute(this.id, this.token), {
@@ -120,6 +135,178 @@ var init_Webhook = __esm({
120
135
  }
121
136
  });
122
137
 
138
+ // src/structures/Message.ts
139
+ var Message_exports = {};
140
+ __export(Message_exports, {
141
+ Message: () => Message
142
+ });
143
+ var import_collection, import_types2, import_builders, Message;
144
+ var init_Message = __esm({
145
+ "src/structures/Message.ts"() {
146
+ "use strict";
147
+ init_Base();
148
+ import_collection = require("@fluxerjs/collection");
149
+ import_types2 = require("@fluxerjs/types");
150
+ import_builders = require("@fluxerjs/builders");
151
+ Message = class _Message extends Base {
152
+ client;
153
+ id;
154
+ channelId;
155
+ guildId;
156
+ author;
157
+ content;
158
+ createdAt;
159
+ editedAt;
160
+ pinned;
161
+ attachments;
162
+ /** Channel where this message was sent. Resolved from cache; null if not cached (e.g. DM channel not in cache). */
163
+ get channel() {
164
+ return this.client.channels.get(this.channelId) ?? null;
165
+ }
166
+ /** Guild where this message was sent. Resolved from cache; null for DMs or if not cached. */
167
+ get guild() {
168
+ return this.guildId ? this.client.guilds.get(this.guildId) ?? null : null;
169
+ }
170
+ /** @param data - API message from POST/PATCH /channels/{id}/messages or gateway MESSAGE_CREATE */
171
+ constructor(client, data) {
172
+ super();
173
+ this.client = client;
174
+ this.id = data.id;
175
+ this.channelId = data.channel_id;
176
+ this.guildId = data.guild_id ?? null;
177
+ this.author = client.getOrCreateUser(data.author);
178
+ this.content = data.content;
179
+ this.createdAt = new Date(data.timestamp);
180
+ this.editedAt = data.edited_timestamp ? new Date(data.edited_timestamp) : null;
181
+ this.pinned = data.pinned;
182
+ this.attachments = new import_collection.Collection();
183
+ for (const a of data.attachments ?? []) this.attachments.set(a.id, a);
184
+ }
185
+ /**
186
+ * Send a message to this channel without replying. Use when you want a standalone message.
187
+ * @param options - Text content or object with content and/or embeds
188
+ * @example
189
+ * await message.send('Pong!');
190
+ * await message.send({ embeds: [embed.toJSON()] });
191
+ */
192
+ async send(options) {
193
+ const body = typeof options === "string" ? { content: options } : options;
194
+ const data = await this.client.rest.post(import_types2.Routes.channelMessages(this.channelId), { body });
195
+ return new _Message(this.client, data);
196
+ }
197
+ /**
198
+ * Send a message to a specific channel. Use for logging, forwarding, or sending to another channel in the guild.
199
+ * @param channelId - Snowflake of the target channel (e.g. log channel ID)
200
+ * @param options - Text content or object with content and/or embeds
201
+ * @example
202
+ * await message.sendTo(logChannelId, 'User ' + message.author.username + ' said: ' + message.content);
203
+ * await message.sendTo(announceChannelId, { embeds: [embed.toJSON()] });
204
+ */
205
+ async sendTo(channelId, options) {
206
+ return this.client.channels.send(channelId, options);
207
+ }
208
+ /**
209
+ * Reply to this message.
210
+ * @param options - Text content or object with content and/or embeds
211
+ */
212
+ async reply(options) {
213
+ const body = typeof options === "string" ? {
214
+ content: options,
215
+ message_reference: {
216
+ channel_id: this.channelId,
217
+ message_id: this.id,
218
+ guild_id: this.guildId ?? void 0
219
+ }
220
+ } : {
221
+ ...options,
222
+ message_reference: {
223
+ channel_id: this.channelId,
224
+ message_id: this.id,
225
+ guild_id: this.guildId ?? void 0
226
+ }
227
+ };
228
+ const data = await this.client.rest.post(import_types2.Routes.channelMessages(this.channelId), { body });
229
+ return new _Message(this.client, data);
230
+ }
231
+ /**
232
+ * Edit this message. Only the author (or admins) can edit.
233
+ * @param options - New content and/or embeds
234
+ */
235
+ async edit(options) {
236
+ const body = {};
237
+ if (options.content !== void 0) body.content = options.content;
238
+ if (options.embeds?.length) {
239
+ body.embeds = options.embeds.map((e) => e instanceof import_builders.EmbedBuilder ? e.toJSON() : e);
240
+ }
241
+ const data = await this.client.rest.patch(import_types2.Routes.channelMessage(this.channelId, this.id), {
242
+ body
243
+ });
244
+ return new _Message(this.client, data);
245
+ }
246
+ /**
247
+ * Re-fetch this message from the API to get the latest content, embeds, reactions, etc.
248
+ * Use when you have a stale Message (e.g. from an old event or cache) and need fresh data.
249
+ * @returns The updated message, or null if deleted or not found
250
+ * @example
251
+ * const updated = await message.fetch();
252
+ * if (updated) console.log('Latest content:', updated.content);
253
+ */
254
+ async fetch() {
255
+ return this.client.channels.fetchMessage(this.channelId, this.id);
256
+ }
257
+ /** Delete this message. */
258
+ async delete() {
259
+ await this.client.rest.delete(import_types2.Routes.channelMessage(this.channelId, this.id));
260
+ }
261
+ /**
262
+ * Format emoji for reaction API: unicode string or "name:id" for custom.
263
+ * For string resolution (e.g. :name:), use client.resolveEmoji; Message methods resolve automatically when guildId is available.
264
+ */
265
+ static formatEmoji(emoji) {
266
+ if (typeof emoji === "string") return emoji;
267
+ return `${emoji.name}:${emoji.id}`;
268
+ }
269
+ resolveEmojiForReaction(emoji) {
270
+ return this.client.resolveEmoji(emoji, this.guildId);
271
+ }
272
+ /**
273
+ * Add a reaction to this message (as the bot).
274
+ * @param emoji - Unicode emoji, custom `{ name, id }`, `:name:`, `name:id`, or `<:name:id>`
275
+ */
276
+ async react(emoji) {
277
+ const emojiStr = await this.resolveEmojiForReaction(emoji);
278
+ const route = `${import_types2.Routes.channelMessageReaction(this.channelId, this.id, emojiStr)}/@me`;
279
+ await this.client.rest.put(route);
280
+ }
281
+ /**
282
+ * Remove the bot's reaction, or a specific user's reaction if userId is provided.
283
+ * @param emoji - Unicode emoji, custom `{ name, id }`, `:name:`, `name:id`, or `<:name:id>`
284
+ * @param userId - If provided, removes that user's reaction (requires moderator permissions)
285
+ */
286
+ async removeReaction(emoji, userId) {
287
+ const emojiStr = await this.resolveEmojiForReaction(emoji);
288
+ const route = `${import_types2.Routes.channelMessageReaction(this.channelId, this.id, emojiStr)}/${userId ?? "@me"}`;
289
+ await this.client.rest.delete(route);
290
+ }
291
+ /**
292
+ * Remove all reactions from this message.
293
+ * Requires moderator permissions.
294
+ */
295
+ async removeAllReactions() {
296
+ await this.client.rest.delete(import_types2.Routes.channelMessageReactions(this.channelId, this.id));
297
+ }
298
+ /**
299
+ * Remove all reactions of a specific emoji from this message.
300
+ * @param emoji - Unicode emoji, custom `{ name, id }`, `:name:`, `name:id`, or `<:name:id>`. Requires moderator permissions.
301
+ */
302
+ async removeReactionEmoji(emoji) {
303
+ const emojiStr = await this.resolveEmojiForReaction(emoji);
304
+ await this.client.rest.delete(import_types2.Routes.channelMessageReaction(this.channelId, this.id, emojiStr));
305
+ }
306
+ };
307
+ }
308
+ });
309
+
123
310
  // src/structures/Channel.ts
124
311
  var Channel_exports = {};
125
312
  __export(Channel_exports, {
@@ -131,13 +318,26 @@ __export(Channel_exports, {
131
318
  TextChannel: () => TextChannel,
132
319
  VoiceChannel: () => VoiceChannel
133
320
  });
134
- var import_types2, Channel, GuildChannel, TextChannel, CategoryChannel, VoiceChannel, LinkChannel, DMChannel;
321
+ var import_types3, Channel, GuildChannel, TextChannel, CategoryChannel, VoiceChannel, LinkChannel, DMChannel;
135
322
  var init_Channel = __esm({
136
323
  "src/structures/Channel.ts"() {
137
324
  "use strict";
325
+ init_MessageManager();
138
326
  init_Base();
139
- import_types2 = require("@fluxerjs/types");
140
- Channel = class extends Base {
327
+ import_types3 = require("@fluxerjs/types");
328
+ Channel = class _Channel extends Base {
329
+ /** Whether this channel has a send method (TextChannel, DMChannel). */
330
+ isSendable() {
331
+ return "send" in this;
332
+ }
333
+ /** Whether this channel is a DM or Group DM. */
334
+ isDM() {
335
+ return this.type === import_types3.ChannelType.DM || this.type === import_types3.ChannelType.GroupDM;
336
+ }
337
+ /** Whether this channel is voice-based (VoiceChannel). */
338
+ isVoice() {
339
+ return "bitrate" in this;
340
+ }
141
341
  /** Create a DM channel from API data (type DM or GroupDM). */
142
342
  static createDM(client, data) {
143
343
  return new DMChannel(client, data);
@@ -159,12 +359,23 @@ var init_Channel = __esm({
159
359
  */
160
360
  static from(client, data) {
161
361
  const type = data.type ?? 0;
162
- if (type === import_types2.ChannelType.GuildText) return new TextChannel(client, data);
163
- if (type === import_types2.ChannelType.GuildCategory) return new CategoryChannel(client, data);
164
- if (type === import_types2.ChannelType.GuildVoice) return new VoiceChannel(client, data);
165
- if (type === import_types2.ChannelType.GuildLink || type === import_types2.ChannelType.GuildLinkExtended) return new LinkChannel(client, data);
362
+ if (type === import_types3.ChannelType.GuildText) return new TextChannel(client, data);
363
+ if (type === import_types3.ChannelType.GuildCategory) return new CategoryChannel(client, data);
364
+ if (type === import_types3.ChannelType.GuildVoice) return new VoiceChannel(client, data);
365
+ if (type === import_types3.ChannelType.GuildLink || type === import_types3.ChannelType.GuildLinkExtended)
366
+ return new LinkChannel(client, data);
166
367
  return new GuildChannel(client, data);
167
368
  }
369
+ /**
370
+ * Create a channel from API data, including DM and GroupDM.
371
+ * Used by ChannelManager.fetch() for GET /channels/{id}.
372
+ */
373
+ static fromOrCreate(client, data) {
374
+ const type = data.type ?? 0;
375
+ if (type === import_types3.ChannelType.DM || type === import_types3.ChannelType.GroupDM)
376
+ return _Channel.createDM(client, data);
377
+ return _Channel.from(client, data);
378
+ }
168
379
  };
169
380
  GuildChannel = class extends Channel {
170
381
  guildId;
@@ -185,7 +396,7 @@ var init_Channel = __esm({
185
396
  */
186
397
  async createWebhook(options) {
187
398
  const { Webhook: Webhook2 } = await Promise.resolve().then(() => (init_Webhook(), Webhook_exports));
188
- const data = await this.client.rest.post(import_types2.Routes.channelWebhooks(this.id), {
399
+ const data = await this.client.rest.post(import_types3.Routes.channelWebhooks(this.id), {
189
400
  body: options,
190
401
  auth: true
191
402
  });
@@ -197,7 +408,7 @@ var init_Channel = __esm({
197
408
  */
198
409
  async fetchWebhooks() {
199
410
  const { Webhook: Webhook2 } = await Promise.resolve().then(() => (init_Webhook(), Webhook_exports));
200
- const data = await this.client.rest.get(import_types2.Routes.channelWebhooks(this.id));
411
+ const data = await this.client.rest.get(import_types3.Routes.channelWebhooks(this.id));
201
412
  const list = Array.isArray(data) ? data : Object.values(data ?? {});
202
413
  return list.map((w) => new Webhook2(this.client, w));
203
414
  }
@@ -221,9 +432,22 @@ var init_Channel = __esm({
221
432
  async send(options) {
222
433
  const body = typeof options === "string" ? { content: options } : options;
223
434
  const { Message: Message2 } = await Promise.resolve().then(() => (init_Message(), Message_exports));
224
- const data = await this.client.rest.post(import_types2.Routes.channelMessages(this.id), { body });
435
+ const data = await this.client.rest.post(import_types3.Routes.channelMessages(this.id), { body });
225
436
  return new Message2(this.client, data);
226
437
  }
438
+ /** Message manager for this channel. Use channel.messages.fetch(messageId). */
439
+ get messages() {
440
+ return new MessageManager(this.client, this.id);
441
+ }
442
+ /**
443
+ * Fetch a message by ID from this channel.
444
+ * @param messageId - Snowflake of the message
445
+ * @returns The message, or null if not found
446
+ * @deprecated Use channel.messages.fetch(messageId) instead.
447
+ */
448
+ async fetchMessage(messageId) {
449
+ return this.client.channels.fetchMessage(this.id, messageId);
450
+ }
227
451
  };
228
452
  CategoryChannel = class extends GuildChannel {
229
453
  };
@@ -258,249 +482,133 @@ var init_Channel = __esm({
258
482
  async send(options) {
259
483
  const body = typeof options === "string" ? { content: options } : options;
260
484
  const { Message: Message2 } = await Promise.resolve().then(() => (init_Message(), Message_exports));
261
- const data = await this.client.rest.post(import_types2.Routes.channelMessages(this.id), { body });
485
+ const data = await this.client.rest.post(import_types3.Routes.channelMessages(this.id), { body });
262
486
  return new Message2(this.client, data);
263
487
  }
488
+ /** Message manager for this channel. Use channel.messages.fetch(messageId). */
489
+ get messages() {
490
+ return new MessageManager(this.client, this.id);
491
+ }
492
+ /**
493
+ * Fetch a message by ID from this DM channel.
494
+ * @param messageId - Snowflake of the message
495
+ * @returns The message, or null if not found
496
+ * @deprecated Use channel.messages.fetch(messageId) instead.
497
+ */
498
+ async fetchMessage(messageId) {
499
+ return this.client.channels.fetchMessage(this.id, messageId);
500
+ }
264
501
  };
265
502
  }
266
503
  });
267
504
 
268
- // src/structures/User.ts
269
- var import_types3, User;
270
- var init_User = __esm({
271
- "src/structures/User.ts"() {
505
+ // src/structures/GuildMember.ts
506
+ var GuildMember_exports = {};
507
+ __export(GuildMember_exports, {
508
+ GuildMember: () => GuildMember
509
+ });
510
+ var import_types5, GuildMember;
511
+ var init_GuildMember = __esm({
512
+ "src/structures/GuildMember.ts"() {
272
513
  "use strict";
273
514
  init_Base();
274
- import_types3 = require("@fluxerjs/types");
275
- init_Constants();
276
- User = class extends Base {
515
+ import_types5 = require("@fluxerjs/types");
516
+ GuildMember = class extends Base {
277
517
  client;
278
518
  id;
279
- username;
280
- discriminator;
281
- globalName;
282
- avatar;
283
- bot;
284
- /** @param data - API user from message author, GET /users/{id}, or GET /users/@me */
285
- constructor(client, data) {
519
+ user;
520
+ guild;
521
+ nick;
522
+ roles;
523
+ joinedAt;
524
+ communicationDisabledUntil;
525
+ /** @param data - API guild member from GET /guilds/{id}/members or GET /guilds/{id}/members/{user_id} */
526
+ constructor(client, data, guild) {
286
527
  super();
287
528
  this.client = client;
288
- this.id = data.id;
289
- this.username = data.username;
290
- this.discriminator = data.discriminator;
291
- this.globalName = data.global_name ?? null;
292
- this.avatar = data.avatar ?? null;
293
- this.bot = !!data.bot;
294
- }
295
- /**
296
- * Get the URL for this user's avatar.
297
- * @param options - Optional `size` and `extension` (default: `png`)
298
- */
299
- avatarURL(options) {
300
- if (!this.avatar) return null;
301
- const ext = options?.extension ?? "png";
302
- const size = options?.size ? `?size=${options.size}` : "";
303
- return `${CDN_URL}/avatars/${this.id}/${this.avatar}.${ext}${size}`;
304
- }
305
- /** Get the avatar URL, or the default avatar if none set. */
306
- displayAvatarURL(options) {
307
- return this.avatarURL(options) ?? `${CDN_URL}/avatars/0/0.png`;
529
+ this.user = client.getOrCreateUser(data.user);
530
+ this.id = data.user.id;
531
+ this.guild = guild;
532
+ this.nick = data.nick ?? null;
533
+ this.roles = data.roles ?? [];
534
+ this.joinedAt = new Date(data.joined_at);
535
+ this.communicationDisabledUntil = data.communication_disabled_until ? new Date(data.communication_disabled_until) : null;
308
536
  }
309
- /** Returns a mention string (e.g. `<@123456>`). */
310
- toString() {
311
- return `<@${this.id}>`;
537
+ /** Nickname, or global name, or username. */
538
+ get displayName() {
539
+ return this.nick ?? this.user.globalName ?? this.user.username;
312
540
  }
313
541
  /**
314
- * Create or get a DM channel with this user.
315
- * Returns the DM channel; use {@link DMChannel.send} to send messages.
542
+ * Add a role to this member.
543
+ * @param roleId - The role ID to add
544
+ * Requires Manage Roles permission.
316
545
  */
317
- async createDM() {
318
- const { DMChannel: DMChannelClass } = await Promise.resolve().then(() => (init_Channel(), Channel_exports));
319
- const data = await this.client.rest.post(import_types3.Routes.userMeChannels(), {
320
- body: { recipient_id: this.id },
321
- auth: true
322
- });
323
- return new DMChannelClass(this.client, data);
546
+ async addRole(roleId) {
547
+ await this.client.rest.put(import_types5.Routes.guildMemberRole(this.guild.id, this.id, roleId));
324
548
  }
325
549
  /**
326
- * Send a DM to this user.
327
- * Convenience method that creates the DM channel and sends the message.
550
+ * Remove a role from this member.
551
+ * @param roleId - The role ID to remove
552
+ * Requires Manage Roles permission.
328
553
  */
329
- async send(options) {
330
- const dm = await this.createDM();
331
- return dm.send(options);
554
+ async removeRole(roleId) {
555
+ await this.client.rest.delete(import_types5.Routes.guildMemberRole(this.guild.id, this.id, roleId));
332
556
  }
333
557
  };
334
558
  }
335
559
  });
336
560
 
337
- // src/structures/Message.ts
338
- var Message_exports = {};
339
- __export(Message_exports, {
340
- Message: () => Message
561
+ // src/structures/Role.ts
562
+ var Role_exports = {};
563
+ __export(Role_exports, {
564
+ Role: () => Role
341
565
  });
342
- var import_collection, import_types4, import_builders, Message;
343
- var init_Message = __esm({
344
- "src/structures/Message.ts"() {
566
+ var Role;
567
+ var init_Role = __esm({
568
+ "src/structures/Role.ts"() {
345
569
  "use strict";
346
570
  init_Base();
347
- import_collection = require("@fluxerjs/collection");
348
- import_types4 = require("@fluxerjs/types");
349
- import_builders = require("@fluxerjs/builders");
350
- init_User();
351
- Message = class _Message extends Base {
571
+ Role = class extends Base {
352
572
  client;
353
573
  id;
354
- channelId;
355
574
  guildId;
356
- author;
357
- content;
358
- createdAt;
359
- editedAt;
360
- pinned;
361
- attachments;
362
- channel;
363
- /** @param data - API message from POST/PATCH /channels/{id}/messages or gateway MESSAGE_CREATE */
364
- constructor(client, data) {
575
+ name;
576
+ color;
577
+ position;
578
+ permissions;
579
+ hoist;
580
+ mentionable;
581
+ unicodeEmoji;
582
+ /** @param client - The client instance */
583
+ /** @param data - API role from GET /guilds/{id}/roles or gateway role events */
584
+ /** @param guildId - The guild this role belongs to */
585
+ constructor(client, data, guildId) {
365
586
  super();
366
587
  this.client = client;
367
588
  this.id = data.id;
368
- this.channelId = data.channel_id;
369
- this.guildId = data.guild_id ?? null;
370
- this.author = new User(client, data.author);
371
- this.content = data.content;
372
- this.createdAt = new Date(data.timestamp);
373
- this.editedAt = data.edited_timestamp ? new Date(data.edited_timestamp) : null;
374
- this.pinned = data.pinned;
375
- this.attachments = new import_collection.Collection();
376
- for (const a of data.attachments ?? []) this.attachments.set(a.id, a);
377
- }
378
- /**
379
- * Reply to this message.
380
- * @param options - Text content or object with content and/or embeds
381
- */
382
- async reply(options) {
383
- const body = typeof options === "string" ? { content: options, message_reference: { channel_id: this.channelId, message_id: this.id, guild_id: this.guildId ?? void 0 } } : { ...options, message_reference: { channel_id: this.channelId, message_id: this.id, guild_id: this.guildId ?? void 0 } };
384
- const data = await this.client.rest.post(import_types4.Routes.channelMessages(this.channelId), { body });
385
- return new _Message(this.client, data);
386
- }
387
- /**
388
- * Edit this message. Only the author (or admins) can edit.
389
- * @param options - New content and/or embeds
390
- */
391
- async edit(options) {
392
- const body = {};
393
- if (options.content !== void 0) body.content = options.content;
394
- if (options.embeds?.length) {
395
- body.embeds = options.embeds.map((e) => e instanceof import_builders.EmbedBuilder ? e.toJSON() : e);
396
- }
397
- const data = await this.client.rest.patch(import_types4.Routes.channelMessage(this.channelId, this.id), { body });
398
- return new _Message(this.client, data);
399
- }
400
- /** Delete this message. */
401
- async delete() {
402
- await this.client.rest.delete(import_types4.Routes.channelMessage(this.channelId, this.id));
403
- }
404
- /**
405
- * Format emoji for reaction API: unicode string or "name:id" for custom.
406
- * @param emoji - Unicode emoji (e.g. "👍") or custom { name, id } or "name:id" string
407
- */
408
- static formatEmoji(emoji) {
409
- if (typeof emoji === "string") return emoji;
410
- return `${emoji.name}:${emoji.id}`;
411
- }
412
- /**
413
- * Add a reaction to this message (as the bot).
414
- * @param emoji - Unicode emoji (e.g. `👍`) or custom emoji `{ name, id }`
415
- */
416
- async react(emoji) {
417
- const emojiStr = _Message.formatEmoji(emoji);
418
- const route = `${import_types4.Routes.channelMessageReaction(this.channelId, this.id, emojiStr)}/@me`;
419
- await this.client.rest.put(route);
420
- }
421
- /**
422
- * Remove the bot's reaction, or a specific user's reaction if userId is provided.
423
- * @param emoji - Unicode emoji or custom `{ name, id }`
424
- * @param userId - If provided, removes that user's reaction (requires moderator permissions)
425
- */
426
- async removeReaction(emoji, userId) {
427
- const emojiStr = _Message.formatEmoji(emoji);
428
- const route = `${import_types4.Routes.channelMessageReaction(this.channelId, this.id, emojiStr)}/${userId ?? "@me"}`;
429
- await this.client.rest.delete(route);
430
- }
431
- /**
432
- * Remove all reactions from this message.
433
- * Requires moderator permissions.
434
- */
435
- async removeAllReactions() {
436
- await this.client.rest.delete(import_types4.Routes.channelMessageReactions(this.channelId, this.id));
589
+ this.guildId = guildId;
590
+ this.name = data.name;
591
+ this.color = data.color;
592
+ this.position = data.position;
593
+ this.permissions = data.permissions;
594
+ this.hoist = !!data.hoist;
595
+ this.mentionable = !!data.mentionable;
596
+ this.unicodeEmoji = data.unicode_emoji ?? null;
437
597
  }
438
- /**
439
- * Remove all reactions of a specific emoji from this message.
440
- * @param emoji - Unicode emoji or custom `{ name, id }`. Requires moderator permissions.
441
- */
442
- async removeReactionEmoji(emoji) {
443
- const emojiStr = _Message.formatEmoji(emoji);
444
- await this.client.rest.delete(import_types4.Routes.channelMessageReaction(this.channelId, this.id, emojiStr));
598
+ /** Returns a mention string (e.g. `<@&123456>`). */
599
+ toString() {
600
+ return `<@&${this.id}>`;
445
601
  }
446
602
  };
447
603
  }
448
604
  });
449
605
 
450
- // src/structures/GuildMember.ts
451
- var GuildMember_exports = {};
452
- __export(GuildMember_exports, {
453
- GuildMember: () => GuildMember
454
- });
455
- var import_types5, GuildMember;
456
- var init_GuildMember = __esm({
457
- "src/structures/GuildMember.ts"() {
606
+ // src/util/Constants.ts
607
+ var CDN_URL;
608
+ var init_Constants = __esm({
609
+ "src/util/Constants.ts"() {
458
610
  "use strict";
459
- init_Base();
460
- init_User();
461
- import_types5 = require("@fluxerjs/types");
462
- GuildMember = class extends Base {
463
- client;
464
- id;
465
- user;
466
- guild;
467
- nick;
468
- roles;
469
- joinedAt;
470
- communicationDisabledUntil;
471
- /** @param data - API guild member from GET /guilds/{id}/members or GET /guilds/{id}/members/{user_id} */
472
- constructor(client, data, guild) {
473
- super();
474
- this.client = client;
475
- this.user = new User(client, data.user);
476
- this.id = data.user.id;
477
- this.guild = guild;
478
- this.nick = data.nick ?? null;
479
- this.roles = data.roles ?? [];
480
- this.joinedAt = new Date(data.joined_at);
481
- this.communicationDisabledUntil = data.communication_disabled_until ? new Date(data.communication_disabled_until) : null;
482
- }
483
- /** Nickname, or global name, or username. */
484
- get displayName() {
485
- return this.nick ?? this.user.globalName ?? this.user.username;
486
- }
487
- /**
488
- * Add a role to this member.
489
- * @param roleId - The role ID to add
490
- * Requires Manage Roles permission.
491
- */
492
- async addRole(roleId) {
493
- await this.client.rest.put(import_types5.Routes.guildMemberRole(this.guild.id, this.id, roleId));
494
- }
495
- /**
496
- * Remove a role from this member.
497
- * @param roleId - The role ID to remove
498
- * Requires Manage Roles permission.
499
- */
500
- async removeRole(roleId) {
501
- await this.client.rest.delete(import_types5.Routes.guildMemberRole(this.guild.id, this.id, roleId));
502
- }
503
- };
611
+ CDN_URL = "https://fluxerusercontent.com";
504
612
  }
505
613
  });
506
614
 
@@ -509,13 +617,15 @@ var Guild_exports = {};
509
617
  __export(Guild_exports, {
510
618
  Guild: () => Guild
511
619
  });
512
- var import_collection2, import_types6, Guild;
620
+ var import_util, import_collection3, import_types6, Guild;
513
621
  var init_Guild = __esm({
514
622
  "src/structures/Guild.ts"() {
515
623
  "use strict";
624
+ import_util = require("@fluxerjs/util");
516
625
  init_Base();
517
- import_collection2 = require("@fluxerjs/collection");
626
+ import_collection3 = require("@fluxerjs/collection");
518
627
  init_GuildMember();
628
+ init_Role();
519
629
  init_Constants();
520
630
  import_types6 = require("@fluxerjs/types");
521
631
  Guild = class extends Base {
@@ -525,8 +635,9 @@ var init_Guild = __esm({
525
635
  icon;
526
636
  banner;
527
637
  ownerId;
528
- members = new import_collection2.Collection();
529
- channels = new import_collection2.Collection();
638
+ members = new import_collection3.Collection();
639
+ channels = new import_collection3.Collection();
640
+ roles = new import_collection3.Collection();
530
641
  /** @param data - API guild from GET /guilds/{id} or gateway GUILD_CREATE */
531
642
  constructor(client, data) {
532
643
  super();
@@ -536,6 +647,9 @@ var init_Guild = __esm({
536
647
  this.icon = data.icon ?? null;
537
648
  this.banner = data.banner ?? null;
538
649
  this.ownerId = data.owner_id;
650
+ for (const r of data.roles ?? []) {
651
+ this.roles.set(r.id, new Role(client, r, this.id));
652
+ }
539
653
  }
540
654
  /** Get the guild icon URL, or null if no icon. */
541
655
  iconURL(options) {
@@ -549,6 +663,47 @@ var init_Guild = __esm({
549
663
  const size = options?.size ? `?size=${options.size}` : "";
550
664
  return `${CDN_URL}/banners/${this.id}/${this.banner}.png${size}`;
551
665
  }
666
+ /**
667
+ * Add a role to a member by user ID. Does not require fetching the member first.
668
+ * @param userId - The user ID of the member
669
+ * @param roleId - The role ID to add (or use guild.resolveRoleId for mention/name resolution)
670
+ * Requires Manage Roles permission.
671
+ */
672
+ async addRoleToMember(userId, roleId) {
673
+ await this.client.rest.put(import_types6.Routes.guildMemberRole(this.id, userId, roleId));
674
+ }
675
+ /**
676
+ * Remove a role from a member by user ID. Does not require fetching the member first.
677
+ * @param userId - The user ID of the member
678
+ * @param roleId - The role ID to remove
679
+ * Requires Manage Roles permission.
680
+ */
681
+ async removeRoleFromMember(userId, roleId) {
682
+ await this.client.rest.delete(import_types6.Routes.guildMemberRole(this.id, userId, roleId));
683
+ }
684
+ /**
685
+ * Resolve a role ID from an argument (role mention, raw ID, or name).
686
+ * Fetches guild roles if name is provided.
687
+ * @param arg - Role mention (@role), role ID, or role name
688
+ * @returns The role ID, or null if not found
689
+ */
690
+ async resolveRoleId(arg) {
691
+ const parsed = (0, import_util.parseRoleMention)(arg);
692
+ if (parsed) return parsed;
693
+ if (/^\d{17,19}$/.test(arg.trim())) return arg.trim();
694
+ const cached = this.roles.find(
695
+ (r) => !!(r.name && r.name.toLowerCase() === arg.trim().toLowerCase())
696
+ );
697
+ if (cached) return cached.id;
698
+ const roles = await this.client.rest.get(import_types6.Routes.guildRoles(this.id));
699
+ const list = Array.isArray(roles) ? roles : Object.values(roles ?? {});
700
+ const role = list.find((r) => !!(r.name && r.name.toLowerCase() === arg.trim().toLowerCase()));
701
+ if (role) {
702
+ this.roles.set(role.id, new Role(this.client, role, this.id));
703
+ return role.id;
704
+ }
705
+ return null;
706
+ }
552
707
  /**
553
708
  * Fetch a guild member by user ID.
554
709
  * @param userId - The user ID of the member to fetch
@@ -575,6 +730,128 @@ var init_Guild = __esm({
575
730
  }
576
731
  });
577
732
 
733
+ // src/structures/User.ts
734
+ var import_types8, User;
735
+ var init_User = __esm({
736
+ "src/structures/User.ts"() {
737
+ "use strict";
738
+ init_Base();
739
+ import_types8 = require("@fluxerjs/types");
740
+ init_Constants();
741
+ User = class extends Base {
742
+ client;
743
+ id;
744
+ username;
745
+ discriminator;
746
+ globalName;
747
+ avatar;
748
+ bot;
749
+ /** @param data - API user from message author, GET /users/{id}, or GET /users/@me */
750
+ constructor(client, data) {
751
+ super();
752
+ this.client = client;
753
+ this.id = data.id;
754
+ this.username = data.username;
755
+ this.discriminator = data.discriminator;
756
+ this.globalName = data.global_name ?? null;
757
+ this.avatar = data.avatar ?? null;
758
+ this.bot = !!data.bot;
759
+ }
760
+ /** Update mutable fields from fresh API data. Used by getOrCreateUser cache. */
761
+ _patch(data) {
762
+ this.username = data.username;
763
+ this.discriminator = data.discriminator;
764
+ this.globalName = data.global_name ?? null;
765
+ this.avatar = data.avatar ?? null;
766
+ }
767
+ /**
768
+ * Get the URL for this user's avatar.
769
+ * @param options - Optional `size` and `extension` (default: `png`)
770
+ */
771
+ avatarURL(options) {
772
+ if (!this.avatar) return null;
773
+ const ext = options?.extension ?? "png";
774
+ const size = options?.size ? `?size=${options.size}` : "";
775
+ return `${CDN_URL}/avatars/${this.id}/${this.avatar}.${ext}${size}`;
776
+ }
777
+ /** Get the avatar URL, or the default avatar if none set. */
778
+ displayAvatarURL(options) {
779
+ return this.avatarURL(options) ?? `${CDN_URL}/avatars/0/0.png`;
780
+ }
781
+ /** Returns a mention string (e.g. `<@123456>`). */
782
+ toString() {
783
+ return `<@${this.id}>`;
784
+ }
785
+ /**
786
+ * Create or get a DM channel with this user.
787
+ * Returns the DM channel; use {@link DMChannel.send} to send messages.
788
+ */
789
+ async createDM() {
790
+ const { DMChannel: DMChannelClass } = await Promise.resolve().then(() => (init_Channel(), Channel_exports));
791
+ const data = await this.client.rest.post(import_types8.Routes.userMeChannels(), {
792
+ body: { recipient_id: this.id },
793
+ auth: true
794
+ });
795
+ return new DMChannelClass(this.client, data);
796
+ }
797
+ /**
798
+ * Send a DM to this user.
799
+ * Convenience method that creates the DM channel and sends the message.
800
+ */
801
+ async send(options) {
802
+ const dm = await this.createDM();
803
+ return dm.send(options);
804
+ }
805
+ };
806
+ }
807
+ });
808
+
809
+ // src/structures/MessageReaction.ts
810
+ var MessageReaction_exports = {};
811
+ __export(MessageReaction_exports, {
812
+ MessageReaction: () => MessageReaction
813
+ });
814
+ var MessageReaction;
815
+ var init_MessageReaction = __esm({
816
+ "src/structures/MessageReaction.ts"() {
817
+ "use strict";
818
+ init_Base();
819
+ MessageReaction = class extends Base {
820
+ client;
821
+ messageId;
822
+ channelId;
823
+ guildId;
824
+ emoji;
825
+ /** Raw gateway payload for low-level access. */
826
+ _data;
827
+ constructor(client, data) {
828
+ super();
829
+ this.client = client;
830
+ this._data = data;
831
+ this.messageId = data.message_id;
832
+ this.channelId = data.channel_id;
833
+ this.guildId = data.guild_id ?? null;
834
+ this.emoji = data.emoji;
835
+ }
836
+ /** Emoji as a string: unicode or "name:id" for custom. */
837
+ get emojiIdentifier() {
838
+ return this.emoji.id ? `${this.emoji.name}:${this.emoji.id}` : this.emoji.name;
839
+ }
840
+ /** Guild where this reaction was added. Resolved from cache; null for DMs or if not cached. */
841
+ get guild() {
842
+ return this.guildId ? this.client.guilds.get(this.guildId) ?? null : null;
843
+ }
844
+ /**
845
+ * Fetch the message this reaction belongs to.
846
+ * Use when you need to edit, delete, or otherwise interact with the message.
847
+ */
848
+ async fetchMessage() {
849
+ return this.client.channels.fetchMessage(this.channelId, this.messageId);
850
+ }
851
+ };
852
+ }
853
+ });
854
+
578
855
  // src/client/ClientUser.ts
579
856
  var ClientUser_exports = {};
580
857
  __export(ClientUser_exports, {
@@ -600,6 +877,7 @@ __export(index_exports, {
600
877
  Base: () => Base,
601
878
  CategoryChannel: () => CategoryChannel,
602
879
  Channel: () => Channel,
880
+ ChannelManager: () => ChannelManager,
603
881
  Client: () => Client,
604
882
  ClientUser: () => ClientUser,
605
883
  DMChannel: () => DMChannel,
@@ -607,14 +885,17 @@ __export(index_exports, {
607
885
  ErrorCodes: () => ErrorCodes,
608
886
  Events: () => Events,
609
887
  FluxerError: () => FluxerError,
610
- GatewayOpcodes: () => import_types8.GatewayOpcodes,
888
+ GatewayOpcodes: () => import_types10.GatewayOpcodes,
611
889
  Guild: () => Guild,
612
890
  GuildChannel: () => GuildChannel,
613
891
  GuildMember: () => GuildMember,
614
892
  LinkChannel: () => LinkChannel,
615
893
  Message: () => Message,
894
+ MessageManager: () => MessageManager,
616
895
  MessagePayload: () => import_builders2.MessagePayload,
617
- Routes: () => import_types8.Routes,
896
+ MessageReaction: () => MessageReaction,
897
+ Role: () => Role,
898
+ Routes: () => import_types10.Routes,
618
899
  TextChannel: () => TextChannel,
619
900
  User: () => User,
620
901
  VoiceChannel: () => VoiceChannel,
@@ -626,8 +907,120 @@ module.exports = __toCommonJS(index_exports);
626
907
  var import_events = require("events");
627
908
  var import_rest = require("@fluxerjs/rest");
628
909
  var import_ws = require("@fluxerjs/ws");
910
+ var import_types9 = require("@fluxerjs/types");
911
+ var import_collection5 = require("@fluxerjs/collection");
912
+
913
+ // src/client/ChannelManager.ts
914
+ var import_collection2 = require("@fluxerjs/collection");
915
+ var import_types4 = require("@fluxerjs/types");
916
+ var ChannelManager = class extends import_collection2.Collection {
917
+ constructor(client) {
918
+ super();
919
+ this.client = client;
920
+ }
921
+ /**
922
+ * Fetch a channel by ID from the API (or return from cache if present).
923
+ * @param channelId - Snowflake of the channel
924
+ * @returns The channel, or null if not found
925
+ * @example
926
+ * const channel = await client.channels.fetch(channelId);
927
+ * if (channel?.isSendable()) await channel.send('Hello!');
928
+ */
929
+ async fetch(channelId) {
930
+ const cached = this.get(channelId);
931
+ if (cached) return cached;
932
+ try {
933
+ const { Channel: Channel2 } = await Promise.resolve().then(() => (init_Channel(), Channel_exports));
934
+ const data = await this.client.rest.get(
935
+ import_types4.Routes.channel(channelId)
936
+ );
937
+ const channel = Channel2.fromOrCreate(this.client, data);
938
+ if (channel) this.set(channel.id, channel);
939
+ return channel;
940
+ } catch {
941
+ return null;
942
+ }
943
+ }
944
+ /**
945
+ * Fetch a message by ID from the API.
946
+ * @param channelId - Snowflake of the channel
947
+ * @param messageId - Snowflake of the message
948
+ * @returns The message, or null if not found
949
+ * @deprecated Use channel.messages.fetch(messageId). Prefer (await client.channels.fetch(channelId))?.messages?.fetch(messageId).
950
+ * @example
951
+ * const channel = await client.channels.fetch(channelId);
952
+ * const message = await channel?.messages?.fetch(messageId);
953
+ */
954
+ async fetchMessage(channelId, messageId) {
955
+ try {
956
+ const { Message: Message2 } = await Promise.resolve().then(() => (init_Message(), Message_exports));
957
+ const data = await this.client.rest.get(
958
+ import_types4.Routes.channelMessage(channelId, messageId)
959
+ );
960
+ return new Message2(this.client, data);
961
+ } catch {
962
+ return null;
963
+ }
964
+ }
965
+ /**
966
+ * Send a message to a channel by ID. Works even when the channel is not cached.
967
+ * Skips the fetch when you only need to send.
968
+ * @param channelId - Snowflake of the channel (text channel or DM)
969
+ * @param payload - Text content or object with content and/or embeds
970
+ * @returns The created message
971
+ * @example
972
+ * await client.channels.send(logChannelId, 'User joined!');
973
+ * await client.channels.send(channelId, { embeds: [embed.toJSON()] });
974
+ */
975
+ async send(channelId, payload) {
976
+ const body = typeof payload === "string" ? { content: payload } : payload;
977
+ const { Message: Message2 } = await Promise.resolve().then(() => (init_Message(), Message_exports));
978
+ const data = await this.client.rest.post(import_types4.Routes.channelMessages(channelId), { body });
979
+ return new Message2(this.client, data);
980
+ }
981
+ };
982
+
983
+ // src/client/GuildManager.ts
984
+ var import_collection4 = require("@fluxerjs/collection");
629
985
  var import_types7 = require("@fluxerjs/types");
630
- var import_collection3 = require("@fluxerjs/collection");
986
+ var GuildManager = class extends import_collection4.Collection {
987
+ constructor(client) {
988
+ super();
989
+ this.client = client;
990
+ }
991
+ /**
992
+ * Fetch a guild by ID from the API (or return from cache if present).
993
+ * @param guildId - Snowflake of the guild
994
+ * @returns The guild, or null if not found
995
+ * @example
996
+ * const guild = await client.guilds.fetch(guildId);
997
+ * if (guild) console.log(guild.name);
998
+ */
999
+ async fetch(guildId) {
1000
+ const cached = this.get(guildId);
1001
+ if (cached) return cached;
1002
+ try {
1003
+ const { Guild: Guild2 } = await Promise.resolve().then(() => (init_Guild(), Guild_exports));
1004
+ const data = await this.client.rest.get(
1005
+ import_types7.Routes.guild(guildId)
1006
+ );
1007
+ const guild = new Guild2(this.client, data);
1008
+ this.set(guild.id, guild);
1009
+ return guild;
1010
+ } catch {
1011
+ return null;
1012
+ }
1013
+ }
1014
+ };
1015
+
1016
+ // src/errors/FluxerError.ts
1017
+ var FluxerError = class _FluxerError extends Error {
1018
+ constructor(message) {
1019
+ super(message);
1020
+ this.name = "FluxerError";
1021
+ Object.setPrototypeOf(this, _FluxerError.prototype);
1022
+ }
1023
+ };
631
1024
 
632
1025
  // src/util/Events.ts
633
1026
  var Events = {
@@ -635,6 +1028,7 @@ var Events = {
635
1028
  MessageCreate: "messageCreate",
636
1029
  MessageUpdate: "messageUpdate",
637
1030
  MessageDelete: "messageDelete",
1031
+ MessageDeleteBulk: "messageDeleteBulk",
638
1032
  MessageReactionAdd: "messageReactionAdd",
639
1033
  MessageReactionRemove: "messageReactionRemove",
640
1034
  MessageReactionRemoveAll: "messageReactionRemoveAll",
@@ -643,25 +1037,285 @@ var Events = {
643
1037
  GuildCreate: "guildCreate",
644
1038
  GuildUpdate: "guildUpdate",
645
1039
  GuildDelete: "guildDelete",
646
- ChannelCreate: "channelCreate",
647
- ChannelUpdate: "channelUpdate",
648
- ChannelDelete: "channelDelete",
1040
+ GuildBanAdd: "guildBanAdd",
1041
+ GuildBanRemove: "guildBanRemove",
1042
+ GuildEmojisUpdate: "guildEmojisUpdate",
1043
+ GuildStickersUpdate: "guildStickersUpdate",
1044
+ GuildIntegrationsUpdate: "guildIntegrationsUpdate",
649
1045
  GuildMemberAdd: "guildMemberAdd",
650
1046
  GuildMemberUpdate: "guildMemberUpdate",
651
1047
  GuildMemberRemove: "guildMemberRemove",
1048
+ GuildRoleCreate: "guildRoleCreate",
1049
+ GuildRoleUpdate: "guildRoleUpdate",
1050
+ GuildRoleDelete: "guildRoleDelete",
1051
+ GuildScheduledEventCreate: "guildScheduledEventCreate",
1052
+ GuildScheduledEventUpdate: "guildScheduledEventUpdate",
1053
+ GuildScheduledEventDelete: "guildScheduledEventDelete",
1054
+ ChannelCreate: "channelCreate",
1055
+ ChannelUpdate: "channelUpdate",
1056
+ ChannelDelete: "channelDelete",
1057
+ ChannelPinsUpdate: "channelPinsUpdate",
1058
+ InviteCreate: "inviteCreate",
1059
+ InviteDelete: "inviteDelete",
1060
+ TypingStart: "typingStart",
1061
+ UserUpdate: "userUpdate",
1062
+ PresenceUpdate: "presenceUpdate",
652
1063
  VoiceStateUpdate: "voiceStateUpdate",
653
1064
  VoiceServerUpdate: "voiceServerUpdate",
654
1065
  VoiceStatesSync: "voiceStatesSync",
1066
+ WebhooksUpdate: "webhooksUpdate",
1067
+ Resumed: "resumed",
655
1068
  Error: "error",
656
1069
  Debug: "debug"
657
1070
  };
658
1071
 
1072
+ // src/client/Client.ts
1073
+ var import_util2 = require("@fluxerjs/util");
1074
+ init_User();
1075
+
1076
+ // src/client/EventHandlerRegistry.ts
1077
+ var handlers = /* @__PURE__ */ new Map();
1078
+ handlers.set("MESSAGE_CREATE", async (client, d) => {
1079
+ const { Message: Message2 } = await Promise.resolve().then(() => (init_Message(), Message_exports));
1080
+ client.emit(Events.MessageCreate, new Message2(client, d));
1081
+ });
1082
+ handlers.set("MESSAGE_UPDATE", async (client, d) => {
1083
+ const { Message: Message2 } = await Promise.resolve().then(() => (init_Message(), Message_exports));
1084
+ client.emit(Events.MessageUpdate, null, new Message2(client, d));
1085
+ });
1086
+ handlers.set("MESSAGE_DELETE", async (client, d) => {
1087
+ const data = d;
1088
+ const channel = client.channels.get(data.channel_id) ?? null;
1089
+ client.emit(Events.MessageDelete, {
1090
+ id: data.id,
1091
+ channelId: data.channel_id,
1092
+ channel
1093
+ });
1094
+ });
1095
+ handlers.set("MESSAGE_REACTION_ADD", async (client, d) => {
1096
+ const data = d;
1097
+ const { MessageReaction: MessageReaction2 } = await Promise.resolve().then(() => (init_MessageReaction(), MessageReaction_exports));
1098
+ const reaction = new MessageReaction2(client, data);
1099
+ const user = client.getOrCreateUser({
1100
+ id: data.user_id,
1101
+ username: "Unknown",
1102
+ discriminator: "0"
1103
+ });
1104
+ client.emit(Events.MessageReactionAdd, reaction, user);
1105
+ });
1106
+ handlers.set("MESSAGE_REACTION_REMOVE", async (client, d) => {
1107
+ const data = d;
1108
+ const { MessageReaction: MessageReaction2 } = await Promise.resolve().then(() => (init_MessageReaction(), MessageReaction_exports));
1109
+ const reaction = new MessageReaction2(client, data);
1110
+ const user = client.getOrCreateUser({
1111
+ id: data.user_id,
1112
+ username: "Unknown",
1113
+ discriminator: "0"
1114
+ });
1115
+ client.emit(Events.MessageReactionRemove, reaction, user);
1116
+ });
1117
+ handlers.set("MESSAGE_REACTION_REMOVE_ALL", async (client, d) => {
1118
+ client.emit(Events.MessageReactionRemoveAll, d);
1119
+ });
1120
+ handlers.set("MESSAGE_REACTION_REMOVE_EMOJI", async (client, d) => {
1121
+ client.emit(
1122
+ Events.MessageReactionRemoveEmoji,
1123
+ d
1124
+ );
1125
+ });
1126
+ handlers.set("GUILD_CREATE", async (client, d) => {
1127
+ const { Guild: Guild2 } = await Promise.resolve().then(() => (init_Guild(), Guild_exports));
1128
+ const { Channel: Channel2 } = await Promise.resolve().then(() => (init_Channel(), Channel_exports));
1129
+ const guild = new Guild2(client, d);
1130
+ client.guilds.set(guild.id, guild);
1131
+ const g = d;
1132
+ for (const ch of g.channels ?? []) {
1133
+ const channel = Channel2.from(client, ch);
1134
+ if (channel) client.channels.set(channel.id, channel);
1135
+ }
1136
+ client.emit(Events.GuildCreate, guild);
1137
+ if (g.voice_states?.length) {
1138
+ client.emit(Events.VoiceStatesSync, { guildId: guild.id, voiceStates: g.voice_states });
1139
+ }
1140
+ });
1141
+ handlers.set("GUILD_UPDATE", async (client, d) => {
1142
+ const { Guild: Guild2 } = await Promise.resolve().then(() => (init_Guild(), Guild_exports));
1143
+ const g = d;
1144
+ const old = client.guilds.get(g.id);
1145
+ const updated = new Guild2(client, g);
1146
+ client.guilds.set(updated.id, updated);
1147
+ client.emit(Events.GuildUpdate, old ?? updated, updated);
1148
+ });
1149
+ handlers.set("GUILD_DELETE", async (client, d) => {
1150
+ const g = d;
1151
+ const guild = client.guilds.get(g.id);
1152
+ if (guild) {
1153
+ client.guilds.delete(g.id);
1154
+ client.emit(Events.GuildDelete, guild);
1155
+ }
1156
+ });
1157
+ handlers.set("CHANNEL_CREATE", async (client, d) => {
1158
+ const { Channel: Channel2 } = await Promise.resolve().then(() => (init_Channel(), Channel_exports));
1159
+ const ch = Channel2.from(client, d);
1160
+ if (ch) {
1161
+ client.channels.set(ch.id, ch);
1162
+ client.emit(Events.ChannelCreate, ch);
1163
+ }
1164
+ });
1165
+ handlers.set("CHANNEL_UPDATE", async (client, d) => {
1166
+ const { Channel: Channel2 } = await Promise.resolve().then(() => (init_Channel(), Channel_exports));
1167
+ const ch = d;
1168
+ const oldCh = client.channels.get(ch.id);
1169
+ const newCh = Channel2.from(client, ch);
1170
+ if (newCh) {
1171
+ client.channels.set(newCh.id, newCh);
1172
+ client.emit(Events.ChannelUpdate, oldCh ?? newCh, newCh);
1173
+ }
1174
+ });
1175
+ handlers.set("CHANNEL_DELETE", async (client, d) => {
1176
+ const ch = d;
1177
+ const channel = client.channels.get(ch.id);
1178
+ if (channel) {
1179
+ client.channels.delete(ch.id);
1180
+ client.emit(Events.ChannelDelete, channel);
1181
+ }
1182
+ });
1183
+ handlers.set("GUILD_MEMBER_ADD", async (client, d) => {
1184
+ const { GuildMember: GuildMember2 } = await Promise.resolve().then(() => (init_GuildMember(), GuildMember_exports));
1185
+ const data = d;
1186
+ const guild = client.guilds.get(data.guild_id);
1187
+ if (guild) {
1188
+ const member = new GuildMember2(client, data, guild);
1189
+ guild.members.set(member.id, member);
1190
+ client.emit(Events.GuildMemberAdd, member);
1191
+ }
1192
+ });
1193
+ handlers.set("GUILD_MEMBER_UPDATE", async (client, d) => {
1194
+ const { GuildMember: GuildMember2 } = await Promise.resolve().then(() => (init_GuildMember(), GuildMember_exports));
1195
+ const data = d;
1196
+ const guild = client.guilds.get(data.guild_id);
1197
+ if (guild) {
1198
+ const oldM = guild.members.get(data.user.id);
1199
+ const newM = new GuildMember2(client, data, guild);
1200
+ guild.members.set(newM.id, newM);
1201
+ client.emit(Events.GuildMemberUpdate, oldM ?? newM, newM);
1202
+ }
1203
+ });
1204
+ handlers.set("GUILD_MEMBER_REMOVE", async (client, d) => {
1205
+ const data = d;
1206
+ const guild = client.guilds.get(data.guild_id);
1207
+ if (guild) {
1208
+ const member = guild.members.get(data.user.id);
1209
+ if (member) {
1210
+ guild.members.delete(data.user.id);
1211
+ client.emit(Events.GuildMemberRemove, member);
1212
+ }
1213
+ }
1214
+ });
1215
+ handlers.set("INTERACTION_CREATE", async (client, d) => {
1216
+ client.emit(Events.InteractionCreate, d);
1217
+ });
1218
+ handlers.set("VOICE_STATE_UPDATE", async (client, d) => {
1219
+ client.emit(Events.VoiceStateUpdate, d);
1220
+ });
1221
+ handlers.set("VOICE_SERVER_UPDATE", async (client, d) => {
1222
+ client.emit(Events.VoiceServerUpdate, d);
1223
+ });
1224
+ handlers.set("MESSAGE_DELETE_BULK", async (client, d) => {
1225
+ client.emit(Events.MessageDeleteBulk, d);
1226
+ });
1227
+ handlers.set("GUILD_BAN_ADD", async (client, d) => {
1228
+ client.emit(Events.GuildBanAdd, d);
1229
+ });
1230
+ handlers.set("GUILD_BAN_REMOVE", async (client, d) => {
1231
+ client.emit(Events.GuildBanRemove, d);
1232
+ });
1233
+ handlers.set("GUILD_EMOJIS_UPDATE", async (client, d) => {
1234
+ client.emit(Events.GuildEmojisUpdate, d);
1235
+ });
1236
+ handlers.set("GUILD_STICKERS_UPDATE", async (client, d) => {
1237
+ client.emit(Events.GuildStickersUpdate, d);
1238
+ });
1239
+ handlers.set("GUILD_INTEGRATIONS_UPDATE", async (client, d) => {
1240
+ client.emit(Events.GuildIntegrationsUpdate, d);
1241
+ });
1242
+ handlers.set("GUILD_ROLE_CREATE", async (client, d) => {
1243
+ const data = d;
1244
+ const guild = client.guilds.get(data.guild_id);
1245
+ if (guild) {
1246
+ const { Role: Role2 } = await Promise.resolve().then(() => (init_Role(), Role_exports));
1247
+ guild.roles.set(data.role.id, new Role2(client, data.role, guild.id));
1248
+ }
1249
+ client.emit(Events.GuildRoleCreate, data);
1250
+ });
1251
+ handlers.set("GUILD_ROLE_UPDATE", async (client, d) => {
1252
+ const data = d;
1253
+ const guild = client.guilds.get(data.guild_id);
1254
+ if (guild) {
1255
+ const { Role: Role2 } = await Promise.resolve().then(() => (init_Role(), Role_exports));
1256
+ guild.roles.set(data.role.id, new Role2(client, data.role, guild.id));
1257
+ }
1258
+ client.emit(Events.GuildRoleUpdate, data);
1259
+ });
1260
+ handlers.set("GUILD_ROLE_DELETE", async (client, d) => {
1261
+ const data = d;
1262
+ const guild = client.guilds.get(data.guild_id);
1263
+ if (guild) guild.roles.delete(data.role_id);
1264
+ client.emit(Events.GuildRoleDelete, data);
1265
+ });
1266
+ handlers.set("GUILD_SCHEDULED_EVENT_CREATE", async (client, d) => {
1267
+ client.emit(Events.GuildScheduledEventCreate, d);
1268
+ });
1269
+ handlers.set("GUILD_SCHEDULED_EVENT_UPDATE", async (client, d) => {
1270
+ client.emit(Events.GuildScheduledEventUpdate, d);
1271
+ });
1272
+ handlers.set("GUILD_SCHEDULED_EVENT_DELETE", async (client, d) => {
1273
+ client.emit(Events.GuildScheduledEventDelete, d);
1274
+ });
1275
+ handlers.set("CHANNEL_PINS_UPDATE", async (client, d) => {
1276
+ client.emit(Events.ChannelPinsUpdate, d);
1277
+ });
1278
+ handlers.set("INVITE_CREATE", async (client, d) => {
1279
+ client.emit(Events.InviteCreate, d);
1280
+ });
1281
+ handlers.set("INVITE_DELETE", async (client, d) => {
1282
+ client.emit(Events.InviteDelete, d);
1283
+ });
1284
+ handlers.set("TYPING_START", async (client, d) => {
1285
+ client.emit(Events.TypingStart, d);
1286
+ });
1287
+ handlers.set("USER_UPDATE", async (client, d) => {
1288
+ const data = d;
1289
+ if (client.user?.id === data.id) {
1290
+ client.user._patch(data);
1291
+ }
1292
+ client.emit(Events.UserUpdate, data);
1293
+ });
1294
+ handlers.set("PRESENCE_UPDATE", async (client, d) => {
1295
+ client.emit(Events.PresenceUpdate, d);
1296
+ });
1297
+ handlers.set("WEBHOOKS_UPDATE", async (client, d) => {
1298
+ client.emit(Events.WebhooksUpdate, d);
1299
+ });
1300
+ handlers.set("RESUMED", async (client) => {
1301
+ client.emit(Events.Resumed);
1302
+ });
1303
+ var eventHandlers = handlers;
1304
+
659
1305
  // src/client/Client.ts
660
1306
  var Client = class extends import_events.EventEmitter {
661
1307
  /** @param options - Token, REST config, WebSocket, presence, etc. */
662
1308
  constructor(options = {}) {
663
1309
  super();
664
1310
  this.options = options;
1311
+ Object.defineProperty(this.channels, "cache", {
1312
+ get: () => this.channels,
1313
+ configurable: true
1314
+ });
1315
+ Object.defineProperty(this.guilds, "cache", {
1316
+ get: () => this.guilds,
1317
+ configurable: true
1318
+ });
665
1319
  this.rest = new import_rest.REST({
666
1320
  api: options.rest?.api ?? "https://api.fluxer.app",
667
1321
  version: options.rest?.version ?? "1",
@@ -669,12 +1323,77 @@ var Client = class extends import_events.EventEmitter {
669
1323
  });
670
1324
  }
671
1325
  rest;
672
- guilds = new import_collection3.Collection();
673
- channels = new import_collection3.Collection();
674
- users = new import_collection3.Collection();
1326
+ guilds = new GuildManager(this);
1327
+ channels = new ChannelManager(this);
1328
+ users = new import_collection5.Collection();
675
1329
  user = null;
676
1330
  readyAt = null;
677
1331
  _ws = null;
1332
+ /**
1333
+ * Resolve an emoji argument to the API format (unicode or "name:id").
1334
+ * Supports: <:name:id>, :name:, name:id, { name, id }, unicode.
1335
+ * When id is missing (e.g. :name:), fetches guild emojis if guildId provided.
1336
+ * @param emoji - Emoji string or object
1337
+ * @param guildId - Guild ID for resolving custom emoji by name (required when id is missing)
1338
+ * @returns API-formatted string for reactions
1339
+ */
1340
+ async resolveEmoji(emoji, guildId) {
1341
+ if (typeof emoji === "object" && emoji.id) {
1342
+ return (0, import_util2.formatEmoji)({ name: emoji.name, id: emoji.id, animated: emoji.animated });
1343
+ }
1344
+ const parsed = (0, import_util2.parseEmoji)(typeof emoji === "string" ? emoji : `:${emoji.name}:`);
1345
+ if (!parsed) throw new Error("Invalid emoji");
1346
+ if (parsed.id) return (0, import_util2.formatEmoji)(parsed);
1347
+ if (guildId) {
1348
+ const emojis = await this.rest.get(import_types9.Routes.guildEmojis(guildId));
1349
+ const list = Array.isArray(emojis) ? emojis : Object.values(emojis ?? {});
1350
+ const found = list.find((e) => e.name && e.name.toLowerCase() === parsed.name.toLowerCase());
1351
+ if (found) return (0, import_util2.formatEmoji)({ ...parsed, id: found.id, animated: found.animated });
1352
+ throw new Error(
1353
+ `Custom emoji ":${parsed.name}:" not found in guild. Use name:id or <:name:id> format.`
1354
+ );
1355
+ }
1356
+ if (/^\w+$/.test(parsed.name)) {
1357
+ throw new Error(
1358
+ `Custom emoji ":${parsed.name}:" requires guild context. Use message.react() in a guild channel, or pass guildId to client.resolveEmoji().`
1359
+ );
1360
+ }
1361
+ return encodeURIComponent(parsed.name);
1362
+ }
1363
+ /**
1364
+ * Fetch a message by channel and message ID. Use when you have IDs (e.g. from a DB).
1365
+ * @param channelId - Snowflake of the channel
1366
+ * @param messageId - Snowflake of the message
1367
+ * @returns The message, or null if not found
1368
+ * @deprecated Use channel.messages.fetch(messageId). For IDs-only: (await client.channels.fetch(channelId))?.messages?.fetch(messageId)
1369
+ * @example
1370
+ * const channel = await client.channels.fetch(channelId);
1371
+ * const message = await channel?.messages?.fetch(messageId);
1372
+ */
1373
+ async fetchMessage(channelId, messageId) {
1374
+ return this.channels.fetchMessage(channelId, messageId);
1375
+ }
1376
+ /**
1377
+ * Send a message to any channel by ID. Shorthand for client.channels.send().
1378
+ * Works even when the channel is not cached.
1379
+ */
1380
+ async sendToChannel(channelId, payload) {
1381
+ return this.channels.send(channelId, payload);
1382
+ }
1383
+ /**
1384
+ * Get or create a User from API data. Caches in client.users.
1385
+ * Updates existing user's username, avatar, etc. when fresh data is provided.
1386
+ */
1387
+ getOrCreateUser(data) {
1388
+ const existing = this.users.get(data.id);
1389
+ if (existing) {
1390
+ existing._patch(data);
1391
+ return existing;
1392
+ }
1393
+ const user = new User(this, data);
1394
+ this.users.set(user.id, user);
1395
+ return user;
1396
+ }
678
1397
  /** WebSocket manager. Throws if not logged in. */
679
1398
  get ws() {
680
1399
  if (!this._ws) throw new Error("Client is not logged in");
@@ -692,145 +1411,8 @@ var Client = class extends import_events.EventEmitter {
692
1411
  if (payload.op !== 0 || !payload.t) return;
693
1412
  const { t: event, d } = payload;
694
1413
  try {
695
- switch (event) {
696
- case "MESSAGE_CREATE": {
697
- const { Message: Message2 } = await Promise.resolve().then(() => (init_Message(), Message_exports));
698
- this.emit(Events.MessageCreate, new Message2(this, d));
699
- break;
700
- }
701
- case "MESSAGE_UPDATE": {
702
- const { Message: Message2 } = await Promise.resolve().then(() => (init_Message(), Message_exports));
703
- this.emit(Events.MessageUpdate, null, new Message2(this, d));
704
- break;
705
- }
706
- case "MESSAGE_DELETE":
707
- this.emit(Events.MessageDelete, { id: d.id, channelId: d.channel_id });
708
- break;
709
- case "MESSAGE_REACTION_ADD":
710
- this.emit(Events.MessageReactionAdd, d);
711
- break;
712
- case "MESSAGE_REACTION_REMOVE":
713
- this.emit(Events.MessageReactionRemove, d);
714
- break;
715
- case "MESSAGE_REACTION_REMOVE_ALL":
716
- this.emit(Events.MessageReactionRemoveAll, d);
717
- break;
718
- case "MESSAGE_REACTION_REMOVE_EMOJI":
719
- this.emit(Events.MessageReactionRemoveEmoji, d);
720
- break;
721
- case "GUILD_CREATE": {
722
- const { Guild: Guild2 } = await Promise.resolve().then(() => (init_Guild(), Guild_exports));
723
- const { Channel: Channel2 } = await Promise.resolve().then(() => (init_Channel(), Channel_exports));
724
- const guild = new Guild2(this, d);
725
- this.guilds.set(guild.id, guild);
726
- const g = d;
727
- for (const ch of g.channels ?? []) {
728
- const channel = Channel2.from(this, ch);
729
- if (channel) this.channels.set(channel.id, channel);
730
- }
731
- this.emit(Events.GuildCreate, guild);
732
- if (g.voice_states?.length) {
733
- this.emit(Events.VoiceStatesSync, { guildId: guild.id, voiceStates: g.voice_states });
734
- }
735
- break;
736
- }
737
- case "GUILD_UPDATE": {
738
- const { Guild: Guild2 } = await Promise.resolve().then(() => (init_Guild(), Guild_exports));
739
- const g = d;
740
- const old = this.guilds.get(g.id);
741
- const updated = new Guild2(this, g);
742
- this.guilds.set(updated.id, updated);
743
- this.emit(Events.GuildUpdate, old ?? updated, updated);
744
- break;
745
- }
746
- case "GUILD_DELETE": {
747
- const g = d;
748
- const guild = this.guilds.get(g.id);
749
- if (guild) {
750
- this.guilds.delete(g.id);
751
- this.emit(Events.GuildDelete, guild);
752
- }
753
- break;
754
- }
755
- case "CHANNEL_CREATE": {
756
- const { Channel: Channel2 } = await Promise.resolve().then(() => (init_Channel(), Channel_exports));
757
- const ch = Channel2.from(this, d);
758
- if (ch) {
759
- this.channels.set(ch.id, ch);
760
- this.emit(Events.ChannelCreate, ch);
761
- }
762
- break;
763
- }
764
- case "CHANNEL_UPDATE": {
765
- const { Channel: Channel2 } = await Promise.resolve().then(() => (init_Channel(), Channel_exports));
766
- const ch = d;
767
- const oldCh = this.channels.get(ch.id);
768
- const newCh = Channel2.from(this, ch);
769
- if (newCh) {
770
- this.channels.set(newCh.id, newCh);
771
- this.emit(Events.ChannelUpdate, oldCh ?? newCh, newCh);
772
- }
773
- break;
774
- }
775
- case "CHANNEL_DELETE": {
776
- const ch = d;
777
- const channel = this.channels.get(ch.id);
778
- if (channel) {
779
- this.channels.delete(ch.id);
780
- this.emit(Events.ChannelDelete, channel);
781
- }
782
- break;
783
- }
784
- case "GUILD_MEMBER_ADD": {
785
- const { GuildMember: GuildMember2 } = await Promise.resolve().then(() => (init_GuildMember(), GuildMember_exports));
786
- const data = d;
787
- const guild = this.guilds.get(data.guild_id);
788
- if (guild) {
789
- const member = new GuildMember2(this, data, guild);
790
- guild.members.set(member.id, member);
791
- this.emit(Events.GuildMemberAdd, member);
792
- }
793
- break;
794
- }
795
- case "GUILD_MEMBER_UPDATE": {
796
- const { GuildMember: GuildMember2 } = await Promise.resolve().then(() => (init_GuildMember(), GuildMember_exports));
797
- const data = d;
798
- const guild = this.guilds.get(data.guild_id);
799
- if (guild) {
800
- const oldM = guild.members.get(data.user.id);
801
- const newM = new GuildMember2(this, data, guild);
802
- guild.members.set(newM.id, newM);
803
- this.emit(Events.GuildMemberUpdate, oldM ?? newM, newM);
804
- }
805
- break;
806
- }
807
- case "GUILD_MEMBER_REMOVE": {
808
- const data = d;
809
- const guild = this.guilds.get(data.guild_id);
810
- if (guild) {
811
- const member = guild.members.get(data.user.id);
812
- if (member) {
813
- guild.members.delete(data.user.id);
814
- this.emit(Events.GuildMemberRemove, member);
815
- }
816
- }
817
- break;
818
- }
819
- case "INTERACTION_CREATE": {
820
- this.emit(Events.InteractionCreate, d);
821
- break;
822
- }
823
- case "VOICE_STATE_UPDATE": {
824
- this.emit(Events.VoiceStateUpdate, d);
825
- break;
826
- }
827
- case "VOICE_SERVER_UPDATE": {
828
- this.emit(Events.VoiceServerUpdate, d);
829
- break;
830
- }
831
- default:
832
- break;
833
- }
1414
+ const handler = eventHandlers.get(event);
1415
+ if (handler) await handler(this, d);
834
1416
  } catch (err) {
835
1417
  this.emit(Events.Error, err instanceof Error ? err : new Error(String(err)));
836
1418
  }
@@ -840,14 +1422,16 @@ var Client = class extends import_events.EventEmitter {
840
1422
  * @param token - Bot token (e.g. from FLUXER_BOT_TOKEN)
841
1423
  */
842
1424
  async login(token) {
1425
+ if (this._ws) {
1426
+ throw new FluxerError("Client is already logged in. Call destroy() first.");
1427
+ }
843
1428
  this.rest.setToken(token);
844
1429
  let intents = this.options.intents ?? 0;
845
1430
  if (intents !== 0) {
846
1431
  if (typeof process !== "undefined" && process.emitWarning) {
847
- process.emitWarning(
848
- "Fluxer does not support intents yet. Value has been set to 0.",
849
- { type: "FluxerIntents" }
850
- );
1432
+ process.emitWarning("Fluxer does not support intents yet. Value has been set to 0.", {
1433
+ type: "FluxerIntents"
1434
+ });
851
1435
  } else {
852
1436
  console.warn("Fluxer does not support intents yet. Value has been set to 0.");
853
1437
  }
@@ -862,28 +1446,38 @@ var Client = class extends import_events.EventEmitter {
862
1446
  WebSocket: this.options.WebSocket
863
1447
  });
864
1448
  this._ws.on("dispatch", ({ payload }) => {
865
- this.handleDispatch(payload);
1449
+ this.handleDispatch(payload).catch(
1450
+ (err) => this.emit(Events.Error, err instanceof Error ? err : new Error(String(err)))
1451
+ );
866
1452
  });
867
- this._ws.on("ready", async ({ data }) => {
868
- const { ClientUser: ClientUser2 } = await Promise.resolve().then(() => (init_ClientUser(), ClientUser_exports));
869
- const { Guild: Guild2 } = await Promise.resolve().then(() => (init_Guild(), Guild_exports));
870
- const { Channel: Channel2 } = await Promise.resolve().then(() => (init_Channel(), Channel_exports));
871
- this.user = new ClientUser2(this, data.user);
872
- for (const g of data.guilds ?? []) {
873
- const guild = new Guild2(this, g);
874
- this.guilds.set(guild.id, guild);
875
- const withCh = g;
876
- for (const ch of withCh.channels ?? []) {
877
- const channel = Channel2.from(this, ch);
878
- if (channel) this.channels.set(channel.id, channel);
879
- }
880
- if (withCh.voice_states?.length) {
881
- this.emit(Events.VoiceStatesSync, { guildId: guild.id, voiceStates: withCh.voice_states });
1453
+ this._ws.on(
1454
+ "ready",
1455
+ async ({
1456
+ data
1457
+ }) => {
1458
+ const { ClientUser: ClientUser2 } = await Promise.resolve().then(() => (init_ClientUser(), ClientUser_exports));
1459
+ const { Guild: Guild2 } = await Promise.resolve().then(() => (init_Guild(), Guild_exports));
1460
+ const { Channel: Channel2 } = await Promise.resolve().then(() => (init_Channel(), Channel_exports));
1461
+ this.user = new ClientUser2(this, data.user);
1462
+ for (const g of data.guilds ?? []) {
1463
+ const guild = new Guild2(this, g);
1464
+ this.guilds.set(guild.id, guild);
1465
+ const withCh = g;
1466
+ for (const ch of withCh.channels ?? []) {
1467
+ const channel = Channel2.from(this, ch);
1468
+ if (channel) this.channels.set(channel.id, channel);
1469
+ }
1470
+ if (withCh.voice_states?.length) {
1471
+ this.emit(Events.VoiceStatesSync, {
1472
+ guildId: guild.id,
1473
+ voiceStates: withCh.voice_states
1474
+ });
1475
+ }
882
1476
  }
1477
+ this.readyAt = /* @__PURE__ */ new Date();
1478
+ this.emit(Events.Ready);
883
1479
  }
884
- this.readyAt = /* @__PURE__ */ new Date();
885
- this.emit(Events.Ready);
886
- });
1480
+ );
887
1481
  this._ws.on("error", ({ error }) => this.emit(Events.Error, error));
888
1482
  this._ws.on("debug", (msg) => this.emit(Events.Debug, msg));
889
1483
  await this._ws.connect();
@@ -907,28 +1501,22 @@ var Client = class extends import_events.EventEmitter {
907
1501
  return this.readyAt !== null && this.user !== null;
908
1502
  }
909
1503
  static get Routes() {
910
- return import_types7.Routes;
1504
+ return import_types9.Routes;
911
1505
  }
912
1506
  };
913
1507
 
914
1508
  // src/index.ts
1509
+ init_MessageManager();
915
1510
  init_ClientUser();
916
1511
  init_Base();
917
1512
  init_User();
918
1513
  init_Guild();
919
1514
  init_Channel();
920
1515
  init_Message();
1516
+ init_MessageReaction();
921
1517
  init_Webhook();
922
1518
  init_GuildMember();
923
-
924
- // src/errors/FluxerError.ts
925
- var FluxerError = class _FluxerError extends Error {
926
- constructor(message) {
927
- super(message);
928
- this.name = "FluxerError";
929
- Object.setPrototypeOf(this, _FluxerError.prototype);
930
- }
931
- };
1519
+ init_Role();
932
1520
 
933
1521
  // src/errors/ErrorCodes.ts
934
1522
  var ErrorCodes = {
@@ -938,13 +1526,14 @@ var ErrorCodes = {
938
1526
 
939
1527
  // src/index.ts
940
1528
  var import_builders2 = require("@fluxerjs/builders");
941
- var import_types8 = require("@fluxerjs/types");
1529
+ var import_types10 = require("@fluxerjs/types");
942
1530
  // Annotate the CommonJS export names for ESM import in node:
943
1531
  0 && (module.exports = {
944
1532
  AttachmentBuilder,
945
1533
  Base,
946
1534
  CategoryChannel,
947
1535
  Channel,
1536
+ ChannelManager,
948
1537
  Client,
949
1538
  ClientUser,
950
1539
  DMChannel,
@@ -958,7 +1547,10 @@ var import_types8 = require("@fluxerjs/types");
958
1547
  GuildMember,
959
1548
  LinkChannel,
960
1549
  Message,
1550
+ MessageManager,
961
1551
  MessagePayload,
1552
+ MessageReaction,
1553
+ Role,
962
1554
  Routes,
963
1555
  TextChannel,
964
1556
  User,