@fluxerjs/core 1.0.9 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/{Channel-ICWNKXBR.mjs → Channel-WJZZSNML.mjs} +3 -1
  2. package/dist/{ClientUser-WWXUMO5O.mjs → ClientUser-DJO2FS7P.mjs} +1 -1
  3. package/dist/Guild-2P77HBQM.mjs +11 -0
  4. package/dist/{GuildBan-M4PA3HAA.mjs → GuildBan-7CXLTPKY.mjs} +1 -1
  5. package/dist/GuildMember-43B5E5CH.mjs +9 -0
  6. package/dist/Message-OFIVTTAZ.mjs +9 -0
  7. package/dist/{MessageReaction-XRPYZDSC.mjs → MessageReaction-V4UZ7OXE.mjs} +1 -1
  8. package/dist/{Role-SVLWIAMN.mjs → Role-5MWSGL66.mjs} +1 -1
  9. package/dist/Webhook-RWDDYW2Q.mjs +10 -0
  10. package/dist/chunk-4XJIM6SC.mjs +315 -0
  11. package/dist/chunk-AH7KYH2Z.mjs +50 -0
  12. package/dist/{chunk-HBF5QEDH.mjs → chunk-CEABHTAF.mjs} +1 -0
  13. package/dist/{chunk-53Y37KRG.mjs → chunk-CJVQNARM.mjs} +44 -10
  14. package/dist/chunk-DQ4TNBPG.mjs +63 -0
  15. package/dist/chunk-DUQAD7F6.mjs +173 -0
  16. package/dist/{chunk-GCIJYVRC.mjs → chunk-JHNKZIHY.mjs} +54 -3
  17. package/dist/{chunk-FJS5FBXO.mjs → chunk-LU2SNC5G.mjs} +172 -13
  18. package/dist/chunk-PM2IUGNR.mjs +29 -0
  19. package/dist/{chunk-RCP27MRC.mjs → chunk-UXIF75BV.mjs} +3 -0
  20. package/dist/{chunk-DSPSRPHF.mjs → chunk-V7LPVPGH.mjs} +123 -18
  21. package/dist/chunk-X6K3ZD62.mjs +53 -0
  22. package/dist/index.d.mts +603 -113
  23. package/dist/index.d.ts +603 -113
  24. package/dist/index.js +1278 -410
  25. package/dist/index.mjs +183 -124
  26. package/package.json +7 -7
  27. package/dist/Guild-TM6YGJWB.mjs +0 -10
  28. package/dist/GuildMember-RZWZ3OCG.mjs +0 -7
  29. package/dist/Message-6IYEYSV6.mjs +0 -7
  30. package/dist/Webhook-32VJD4AL.mjs +0 -7
  31. package/dist/chunk-GFUJVQ7L.mjs +0 -64
  32. package/dist/chunk-SQVCCSNN.mjs +0 -41
  33. package/dist/chunk-X77DFNE3.mjs +0 -136
@@ -1,11 +1,74 @@
1
+ import {
2
+ Events
3
+ } from "./chunk-AH7KYH2Z.mjs";
4
+ import {
5
+ buildSendBody
6
+ } from "./chunk-PM2IUGNR.mjs";
1
7
  import {
2
8
  Base
3
9
  } from "./chunk-XNS4O6QJ.mjs";
4
10
 
5
11
  // src/structures/Message.ts
6
- import { Collection } from "@fluxerjs/collection";
12
+ import { Collection as Collection2 } from "@fluxerjs/collection";
7
13
  import { MessageType, Routes } from "@fluxerjs/types";
8
14
  import { EmbedBuilder } from "@fluxerjs/builders";
15
+
16
+ // src/util/ReactionCollector.ts
17
+ import { EventEmitter } from "events";
18
+ import { Collection } from "@fluxerjs/collection";
19
+ var ReactionCollector = class extends EventEmitter {
20
+ client;
21
+ messageId;
22
+ channelId;
23
+ options;
24
+ collected = new Collection();
25
+ _timeout = null;
26
+ _ended = false;
27
+ _listener;
28
+ constructor(client, messageId, channelId, options = {}) {
29
+ super();
30
+ this.client = client;
31
+ this.messageId = messageId;
32
+ this.channelId = channelId;
33
+ this.options = {
34
+ filter: options.filter ?? (() => true),
35
+ time: options.time ?? 0,
36
+ max: options.max ?? 0
37
+ };
38
+ this._listener = (reaction, user, _msgId, chId, _emoji, userId) => {
39
+ if (this._ended || reaction.messageId !== this.messageId || chId !== this.channelId) return;
40
+ if (!this.options.filter(reaction, user)) return;
41
+ const key = `${userId}:${reaction.emoji.id ?? reaction.emoji.name}`;
42
+ this.collected.set(key, { reaction, user });
43
+ this.emit("collect", reaction, user);
44
+ if (this.options.max > 0 && this.collected.size >= this.options.max) {
45
+ this.stop("limit");
46
+ }
47
+ };
48
+ this.client.on(Events.MessageReactionAdd, this._listener);
49
+ if (this.options.time > 0) {
50
+ this._timeout = setTimeout(() => this.stop("time"), this.options.time);
51
+ }
52
+ }
53
+ stop(reason = "user") {
54
+ if (this._ended) return;
55
+ this._ended = true;
56
+ this.client.off(Events.MessageReactionAdd, this._listener);
57
+ if (this._timeout) {
58
+ clearTimeout(this._timeout);
59
+ this._timeout = null;
60
+ }
61
+ this.emit("end", this.collected, reason);
62
+ }
63
+ on(event, listener) {
64
+ return super.on(event, listener);
65
+ }
66
+ emit(event, ...args) {
67
+ return super.emit(event, ...args);
68
+ }
69
+ };
70
+
71
+ // src/structures/Message.ts
9
72
  var Message = class _Message extends Base {
10
73
  client;
11
74
  id;
@@ -28,6 +91,14 @@ var Message = class _Message extends Base {
28
91
  messageSnapshots;
29
92
  call;
30
93
  referencedMessage;
94
+ /** Webhook ID if this message was sent via webhook. Null otherwise. */
95
+ webhookId;
96
+ /** Users mentioned in this message. */
97
+ mentions;
98
+ /** Role IDs mentioned in this message. */
99
+ mentionRoles;
100
+ /** Client-side nonce for acknowledgment. Null if not provided. */
101
+ nonce;
31
102
  /** Channel where this message was sent. Resolved from cache; null if not cached (e.g. DM channel not in cache). */
32
103
  get channel() {
33
104
  return this.client.channels.get(this.channelId) ?? null;
@@ -48,7 +119,7 @@ var Message = class _Message extends Base {
48
119
  this.createdAt = new Date(data.timestamp);
49
120
  this.editedAt = data.edited_timestamp ? new Date(data.edited_timestamp) : null;
50
121
  this.pinned = data.pinned;
51
- this.attachments = new Collection();
122
+ this.attachments = new Collection2();
52
123
  for (const a of data.attachments ?? []) this.attachments.set(a.id, a);
53
124
  this.type = data.type ?? MessageType.Default;
54
125
  this.flags = data.flags ?? 0;
@@ -61,17 +132,24 @@ var Message = class _Message extends Base {
61
132
  this.messageSnapshots = data.message_snapshots ?? [];
62
133
  this.call = data.call ?? null;
63
134
  this.referencedMessage = data.referenced_message ? new _Message(client, data.referenced_message) : null;
135
+ this.webhookId = data.webhook_id ?? null;
136
+ this.mentions = (data.mentions ?? []).map((u) => client.getOrCreateUser(u));
137
+ this.mentionRoles = data.mention_roles ?? [];
138
+ this.nonce = data.nonce ?? null;
64
139
  }
65
140
  /**
66
141
  * Send a message to this channel without replying. Use when you want a standalone message.
67
- * @param options - Text content or object with content and/or embeds
142
+ * @param options - Text content or object with content, embeds, and/or files
68
143
  * @example
69
144
  * await message.send('Pong!');
70
145
  * await message.send({ embeds: [embed.toJSON()] });
146
+ * await message.send({ content: 'File', files: [{ name: 'data.txt', data }] });
71
147
  */
72
148
  async send(options) {
73
- const body = typeof options === "string" ? { content: options } : options;
74
- const data = await this.client.rest.post(Routes.channelMessages(this.channelId), { body });
149
+ const opts = typeof options === "string" ? { content: options } : options;
150
+ const body = buildSendBody(options);
151
+ const postOptions = opts.files?.length ? { body, files: opts.files } : { body };
152
+ const data = await this.client.rest.post(Routes.channelMessages(this.channelId), postOptions);
75
153
  return new _Message(this.client, data);
76
154
  }
77
155
  /**
@@ -87,25 +165,21 @@ var Message = class _Message extends Base {
87
165
  }
88
166
  /**
89
167
  * Reply to this message.
90
- * @param options - Text content or object with content and/or embeds
168
+ * @param options - Text content or object with content, embeds, and/or files
91
169
  */
92
170
  async reply(options) {
93
- const body = typeof options === "string" ? {
94
- content: options,
95
- message_reference: {
96
- channel_id: this.channelId,
97
- message_id: this.id,
98
- guild_id: this.guildId ?? void 0
99
- }
100
- } : {
101
- ...options,
171
+ const opts = typeof options === "string" ? { content: options } : options;
172
+ const base = buildSendBody(options);
173
+ const body = {
174
+ ...base,
102
175
  message_reference: {
103
176
  channel_id: this.channelId,
104
177
  message_id: this.id,
105
178
  guild_id: this.guildId ?? void 0
106
179
  }
107
180
  };
108
- const data = await this.client.rest.post(Routes.channelMessages(this.channelId), { body });
181
+ const postOptions = opts.files?.length ? { body, files: opts.files } : { body };
182
+ const data = await this.client.rest.post(Routes.channelMessages(this.channelId), postOptions);
109
183
  return new _Message(this.client, data);
110
184
  }
111
185
  /**
@@ -123,13 +197,26 @@ var Message = class _Message extends Base {
123
197
  });
124
198
  return new _Message(this.client, data);
125
199
  }
200
+ /**
201
+ * Create a reaction collector for this message.
202
+ * Collects reactions matching the filter until time expires or max is reached.
203
+ * @param options - Filter, time (ms), and max count
204
+ * @example
205
+ * const collector = message.createReactionCollector({ filter: (r, u) => u.id === userId, time: 10000 });
206
+ * collector.on('collect', (reaction, user) => console.log(user.username, 'reacted with', reaction.emoji.name));
207
+ * collector.on('end', (collected, reason) => { ... });
208
+ */
209
+ createReactionCollector(options) {
210
+ return new ReactionCollector(this.client, this.id, this.channelId, options);
211
+ }
126
212
  /**
127
213
  * Re-fetch this message from the API to get the latest content, embeds, reactions, etc.
128
214
  * Use when you have a stale Message (e.g. from an old event or cache) and need fresh data.
129
- * @returns The updated message, or null if deleted or not found
215
+ * @returns The updated message
216
+ * @throws FluxerError with MESSAGE_NOT_FOUND if the message was deleted or does not exist
130
217
  * @example
131
218
  * const updated = await message.fetch();
132
- * if (updated) console.log('Latest content:', updated.content);
219
+ * console.log('Latest content:', updated.content);
133
220
  */
134
221
  async fetch() {
135
222
  return this.client.channels.fetchMessage(this.channelId, this.id);
@@ -193,8 +280,26 @@ var Message = class _Message extends Base {
193
280
  const emojiStr = await this.resolveEmojiForReaction(emoji);
194
281
  await this.client.rest.delete(Routes.channelMessageReaction(this.channelId, this.id, emojiStr));
195
282
  }
283
+ /**
284
+ * Fetch users who reacted with the given emoji.
285
+ * @param emoji - Unicode emoji or custom `{ name, id }`
286
+ * @param options - limit (1–100), after (user ID for pagination)
287
+ * @returns Array of User objects
288
+ */
289
+ async fetchReactionUsers(emoji, options) {
290
+ const emojiStr = await this.resolveEmojiForReaction(emoji);
291
+ const params = new URLSearchParams();
292
+ if (options?.limit != null) params.set("limit", String(options.limit));
293
+ if (options?.after) params.set("after", options.after);
294
+ const qs = params.toString();
295
+ const route = Routes.channelMessageReaction(this.channelId, this.id, emojiStr) + (qs ? `?${qs}` : "");
296
+ const data = await this.client.rest.get(route);
297
+ const list = Array.isArray(data) ? data : data?.users ?? [];
298
+ return list.map((u) => this.client.getOrCreateUser(u));
299
+ }
196
300
  };
197
301
 
198
302
  export {
303
+ ReactionCollector,
199
304
  Message
200
305
  };
@@ -0,0 +1,53 @@
1
+ import {
2
+ CDN_URL
3
+ } from "./chunk-HQMYRYMY.mjs";
4
+
5
+ // src/util/cdn.ts
6
+ function getExtension(hash, options) {
7
+ const ext = options?.extension ?? "png";
8
+ if (hash?.startsWith("a_")) return "gif";
9
+ return ext;
10
+ }
11
+ function appendSize(options) {
12
+ return options?.size ? `?size=${options.size}` : "";
13
+ }
14
+ function cdnAvatarURL(userId, avatarHash, options) {
15
+ if (!avatarHash) return null;
16
+ const ext = getExtension(avatarHash, options);
17
+ const size = appendSize(options);
18
+ return `${CDN_URL}/avatars/${userId}/${avatarHash}.${ext}${size}`;
19
+ }
20
+ function cdnDisplayAvatarURL(userId, avatarHash, options) {
21
+ return cdnAvatarURL(userId, avatarHash, options) ?? `${CDN_URL}/avatars/0/0.png`;
22
+ }
23
+ function cdnBannerURL(resourceId, bannerHash, options) {
24
+ if (!bannerHash) return null;
25
+ const ext = getExtension(bannerHash, options);
26
+ const size = appendSize(options);
27
+ return `${CDN_URL}/banners/${resourceId}/${bannerHash}.${ext}${size}`;
28
+ }
29
+ function cdnMemberAvatarURL(guildId, userId, avatarHash, options) {
30
+ if (!avatarHash) return null;
31
+ const ext = getExtension(avatarHash, options);
32
+ const size = appendSize(options);
33
+ return `${CDN_URL}/guilds/${guildId}/users/${userId}/avatars/${avatarHash}.${ext}${size}`;
34
+ }
35
+ function cdnMemberBannerURL(guildId, userId, bannerHash, options) {
36
+ if (!bannerHash) return null;
37
+ const ext = getExtension(bannerHash, options);
38
+ const size = appendSize(options);
39
+ return `${CDN_URL}/guilds/${guildId}/users/${userId}/banners/${bannerHash}.${ext}${size}`;
40
+ }
41
+ function cdnDefaultAvatarURL(discriminatorIndex) {
42
+ const index = discriminatorIndex != null ? discriminatorIndex % 5 : 0;
43
+ return `${CDN_URL}/avatars/0/${index}.png`;
44
+ }
45
+
46
+ export {
47
+ cdnAvatarURL,
48
+ cdnDisplayAvatarURL,
49
+ cdnBannerURL,
50
+ cdnMemberAvatarURL,
51
+ cdnMemberBannerURL,
52
+ cdnDefaultAvatarURL
53
+ };