@fluxerjs/core 1.0.8 → 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 (37) hide show
  1. package/dist/{Channel-TWPDKW2P.mjs → Channel-WJZZSNML.mjs} +3 -1
  2. package/dist/{ClientUser-2K2BACK7.mjs → ClientUser-DJO2FS7P.mjs} +1 -1
  3. package/dist/Guild-2P77HBQM.mjs +11 -0
  4. package/dist/GuildBan-7CXLTPKY.mjs +7 -0
  5. package/dist/GuildMember-43B5E5CH.mjs +9 -0
  6. package/dist/{Message-G2QIKZQK.mjs → Invite-UM5BU5A6.mjs} +3 -3
  7. package/dist/Message-OFIVTTAZ.mjs +9 -0
  8. package/dist/{MessageReaction-XRPYZDSC.mjs → MessageReaction-V4UZ7OXE.mjs} +1 -1
  9. package/dist/{Role-SVLWIAMN.mjs → Role-5MWSGL66.mjs} +1 -1
  10. package/dist/Webhook-RWDDYW2Q.mjs +10 -0
  11. package/dist/chunk-4XJIM6SC.mjs +315 -0
  12. package/dist/chunk-AH7KYH2Z.mjs +50 -0
  13. package/dist/{chunk-HBF5QEDH.mjs → chunk-CEABHTAF.mjs} +1 -0
  14. package/dist/chunk-CJVQNARM.mjs +145 -0
  15. package/dist/chunk-DQ4TNBPG.mjs +63 -0
  16. package/dist/chunk-DUQAD7F6.mjs +173 -0
  17. package/dist/{chunk-4GCZFOS5.mjs → chunk-JHNKZIHY.mjs} +54 -3
  18. package/dist/chunk-LU2SNC5G.mjs +392 -0
  19. package/dist/chunk-PM2IUGNR.mjs +29 -0
  20. package/dist/chunk-QEXIYXXU.mjs +62 -0
  21. package/dist/chunk-UXIF75BV.mjs +36 -0
  22. package/dist/chunk-V7LPVPGH.mjs +305 -0
  23. package/dist/chunk-X6K3ZD62.mjs +53 -0
  24. package/dist/index.d.mts +802 -160
  25. package/dist/index.d.ts +802 -160
  26. package/dist/index.js +1467 -262
  27. package/dist/index.mjs +292 -119
  28. package/package.json +7 -7
  29. package/dist/Guild-CMZGA6DW.mjs +0 -10
  30. package/dist/GuildMember-DW2N6ITI.mjs +0 -7
  31. package/dist/Webhook-2MQESB7Z.mjs +0 -7
  32. package/dist/chunk-CO5EL5LH.mjs +0 -168
  33. package/dist/chunk-CZIO2D7F.mjs +0 -207
  34. package/dist/chunk-JVEOQFUX.mjs +0 -52
  35. package/dist/chunk-SQVCCSNN.mjs +0 -41
  36. package/dist/chunk-TJVZEILY.mjs +0 -120
  37. package/dist/chunk-ZGMM6IPQ.mjs +0 -79
@@ -0,0 +1,173 @@
1
+ import {
2
+ cdnMemberAvatarURL,
3
+ cdnMemberBannerURL
4
+ } from "./chunk-X6K3ZD62.mjs";
5
+ import {
6
+ Base
7
+ } from "./chunk-XNS4O6QJ.mjs";
8
+
9
+ // src/structures/GuildMember.ts
10
+ import { PermissionFlagsMap } from "@fluxerjs/util";
11
+ import { Routes } from "@fluxerjs/types";
12
+
13
+ // src/util/permissions.ts
14
+ import { OverwriteType } from "@fluxerjs/types";
15
+ import { ALL_PERMISSIONS_BIGINT } from "@fluxerjs/util";
16
+ function computePermissions(basePermissions, overwrites, memberRoles, memberId, isOwner) {
17
+ if (isOwner) return ALL_PERMISSIONS_BIGINT;
18
+ let perms = basePermissions;
19
+ for (const overwrite of overwrites ?? []) {
20
+ const applies = overwrite.type === OverwriteType.Role && memberRoles.includes(overwrite.id) || overwrite.type === OverwriteType.Member && overwrite.id === memberId;
21
+ if (!applies) continue;
22
+ const allow = BigInt(overwrite.allow || "0");
23
+ const deny = BigInt(overwrite.deny || "0");
24
+ perms = perms & ~deny | allow;
25
+ }
26
+ return perms;
27
+ }
28
+ function hasPermission(bitfield, permission) {
29
+ const Administrator = 1n << 3n;
30
+ if ((bitfield & Administrator) !== 0n) return true;
31
+ return (bitfield & permission) === permission;
32
+ }
33
+
34
+ // src/structures/GuildMember.ts
35
+ var GuildMember = class extends Base {
36
+ client;
37
+ id;
38
+ user;
39
+ guild;
40
+ nick;
41
+ roles;
42
+ joinedAt;
43
+ communicationDisabledUntil;
44
+ mute;
45
+ deaf;
46
+ avatar;
47
+ banner;
48
+ accentColor;
49
+ profileFlags;
50
+ /** @param data - API guild member from GET /guilds/{id}/members or GET /guilds/{id}/members/{user_id} */
51
+ constructor(client, data, guild) {
52
+ super();
53
+ this.client = client;
54
+ this.user = client.getOrCreateUser(data.user);
55
+ this.id = data.user.id;
56
+ this.guild = guild;
57
+ this.nick = data.nick ?? null;
58
+ this.roles = data.roles ?? [];
59
+ this.joinedAt = new Date(data.joined_at);
60
+ this.communicationDisabledUntil = data.communication_disabled_until ? new Date(data.communication_disabled_until) : null;
61
+ this.mute = data.mute ?? false;
62
+ this.deaf = data.deaf ?? false;
63
+ this.avatar = data.avatar ?? null;
64
+ this.banner = data.banner ?? null;
65
+ this.accentColor = data.accent_color ?? null;
66
+ this.profileFlags = data.profile_flags ?? null;
67
+ }
68
+ /** Nickname, or global name, or username. */
69
+ get displayName() {
70
+ return this.nick ?? this.user.globalName ?? this.user.username;
71
+ }
72
+ /**
73
+ * Get the guild-specific avatar URL for this member.
74
+ * Returns null if the member has no guild avatar (use displayAvatarURL for fallback).
75
+ */
76
+ avatarURL(options) {
77
+ return cdnMemberAvatarURL(this.guild.id, this.id, this.avatar, options);
78
+ }
79
+ /**
80
+ * Get the avatar URL to display for this member.
81
+ * Uses guild-specific avatar if set, otherwise falls back to the user's avatar.
82
+ */
83
+ displayAvatarURL(options) {
84
+ return this.avatarURL(options) ?? this.user.displayAvatarURL(options);
85
+ }
86
+ /**
87
+ * Get the guild-specific banner URL for this member.
88
+ * Returns null if the member has no guild banner.
89
+ */
90
+ bannerURL(options) {
91
+ return cdnMemberBannerURL(this.guild.id, this.id, this.banner, options);
92
+ }
93
+ /**
94
+ * Add a role to this member.
95
+ * @param roleId - The role ID to add
96
+ * Requires Manage Roles permission.
97
+ */
98
+ async addRole(roleId) {
99
+ await this.client.rest.put(Routes.guildMemberRole(this.guild.id, this.id, roleId));
100
+ }
101
+ /**
102
+ * Remove a role from this member.
103
+ * @param roleId - The role ID to remove
104
+ * Requires Manage Roles permission.
105
+ */
106
+ async removeRole(roleId) {
107
+ await this.client.rest.delete(Routes.guildMemberRole(this.guild.id, this.id, roleId));
108
+ }
109
+ /**
110
+ * Get the member's guild-level permissions (from roles only, no channel overwrites).
111
+ * Use this for server-wide permission checks (e.g. ban, kick, manage roles).
112
+ * @returns Object with has(permission) to check specific permissions
113
+ * @example
114
+ * const perms = member.permissions;
115
+ * if (perms.has(PermissionFlags.BanMembers)) { ... }
116
+ */
117
+ get permissions() {
118
+ const base = this._computeBasePermissions();
119
+ const ownerId = this.guild.ownerId;
120
+ const isOwner = ownerId != null && ownerId !== "" && String(ownerId) === String(this.id);
121
+ const perms = computePermissions(base, [], [], this.id, isOwner);
122
+ return {
123
+ has(permission) {
124
+ const perm = typeof permission === "number" ? permission : PermissionFlagsMap[String(permission)];
125
+ if (perm === void 0) return false;
126
+ return hasPermission(perms, BigInt(perm));
127
+ }
128
+ };
129
+ }
130
+ /**
131
+ * Compute the member's effective permissions in a guild channel.
132
+ * Applies role permissions and channel overwrites.
133
+ * @param channel - The guild channel to check permissions for
134
+ * @returns Object with has(permission) to check specific permissions
135
+ * @example
136
+ * const perms = member.permissionsIn(channel);
137
+ * if (perms.has(PermissionFlags.SendMessages)) { ... }
138
+ */
139
+ permissionsIn(channel) {
140
+ const base = this._computeBasePermissions();
141
+ const ownerId = this.guild.ownerId;
142
+ const isOwner = ownerId != null && ownerId !== "" && String(ownerId) === String(this.id);
143
+ const perms = computePermissions(
144
+ base,
145
+ channel.permissionOverwrites,
146
+ this.roles,
147
+ this.id,
148
+ isOwner
149
+ );
150
+ return {
151
+ has(permission) {
152
+ const perm = typeof permission === "number" ? permission : PermissionFlagsMap[String(permission)];
153
+ if (perm === void 0) return false;
154
+ return hasPermission(perms, BigInt(perm));
155
+ }
156
+ };
157
+ }
158
+ _computeBasePermissions() {
159
+ let base = 0n;
160
+ const everyone = this.guild.roles.get(this.guild.id);
161
+ if (everyone) base |= BigInt(everyone.permissions);
162
+ for (const roleId of this.roles) {
163
+ if (roleId === this.guild.id) continue;
164
+ const role = this.guild.roles.get(roleId);
165
+ if (role) base |= BigInt(role.permissions);
166
+ }
167
+ return base;
168
+ }
169
+ };
170
+
171
+ export {
172
+ GuildMember
173
+ };
@@ -15,6 +15,14 @@ var User = class extends Base {
15
15
  globalName;
16
16
  avatar;
17
17
  bot;
18
+ /** RGB avatar color (e.g. 7577782). Null if not set. */
19
+ avatarColor;
20
+ /** Public flags bitfield. Null if not set. */
21
+ flags;
22
+ /** Whether this is an official system user. */
23
+ system;
24
+ /** Banner hash (from profile, member, or invite context). Null when not available. */
25
+ banner;
18
26
  /** @param data - API user from message author, GET /users/{id}, or GET /users/@me */
19
27
  constructor(client, data) {
20
28
  super();
@@ -25,6 +33,10 @@ var User = class extends Base {
25
33
  this.globalName = data.global_name ?? null;
26
34
  this.avatar = data.avatar ?? null;
27
35
  this.bot = !!data.bot;
36
+ this.avatarColor = data.avatar_color ?? null;
37
+ this.flags = data.flags ?? data.public_flags ?? null;
38
+ this.system = !!data.system;
39
+ this.banner = data.banner ?? null;
28
40
  }
29
41
  /** Update mutable fields from fresh API data. Used by getOrCreateUser cache. */
30
42
  _patch(data) {
@@ -32,14 +44,18 @@ var User = class extends Base {
32
44
  this.discriminator = data.discriminator;
33
45
  this.globalName = data.global_name ?? null;
34
46
  this.avatar = data.avatar ?? null;
47
+ if (data.avatar_color !== void 0) this.avatarColor = data.avatar_color;
48
+ if (data.flags !== void 0) this.flags = data.flags;
49
+ if (data.banner !== void 0) this.banner = data.banner;
35
50
  }
36
51
  /**
37
52
  * Get the URL for this user's avatar.
38
- * @param options - Optional `size` and `extension` (default: `png`)
53
+ * Auto-detects animated avatars (hash starting with `a_`) and uses gif extension.
54
+ * @param options - Optional `size` and `extension` (default: png, or gif for animated)
39
55
  */
40
56
  avatarURL(options) {
41
57
  if (!this.avatar) return null;
42
- const ext = options?.extension ?? "png";
58
+ const ext = this.avatar.startsWith("a_") ? "gif" : options?.extension ?? "png";
43
59
  const size = options?.size ? `?size=${options.size}` : "";
44
60
  return `${CDN_URL}/avatars/${this.id}/${this.avatar}.${ext}${size}`;
45
61
  }
@@ -47,6 +63,16 @@ var User = class extends Base {
47
63
  displayAvatarURL(options) {
48
64
  return this.avatarURL(options) ?? `${CDN_URL}/avatars/0/0.png`;
49
65
  }
66
+ /**
67
+ * Get the URL for this user's banner.
68
+ * Returns null if the user has no banner (only available when fetched from profile/member context).
69
+ */
70
+ bannerURL(options) {
71
+ if (!this.banner) return null;
72
+ const ext = this.banner.startsWith("a_") ? "gif" : options?.extension ?? "png";
73
+ const size = options?.size ? `?size=${options.size}` : "";
74
+ return `${CDN_URL}/banners/${this.id}/${this.banner}.${ext}${size}`;
75
+ }
50
76
  /** Returns a mention string (e.g. `<@123456>`). */
51
77
  toString() {
52
78
  return `<@${this.id}>`;
@@ -56,7 +82,7 @@ var User = class extends Base {
56
82
  * Returns the DM channel; use {@link DMChannel.send} to send messages.
57
83
  */
58
84
  async createDM() {
59
- const { DMChannel: DMChannelClass } = await import("./Channel-TWPDKW2P.mjs");
85
+ const { DMChannel: DMChannelClass } = await import("./Channel-WJZZSNML.mjs");
60
86
  const data = await this.client.rest.post(Routes.userMeChannels(), {
61
87
  body: { recipient_id: this.id },
62
88
  auth: true
@@ -74,10 +100,35 @@ var User = class extends Base {
74
100
  };
75
101
 
76
102
  // src/client/ClientUser.ts
103
+ import { Routes as Routes2 } from "@fluxerjs/types";
77
104
  var ClientUser = class extends User {
78
105
  constructor(client, data) {
79
106
  super(client, { ...data });
80
107
  }
108
+ /**
109
+ * Fetch guilds the bot is a member of.
110
+ * @returns Array of Guild objects (cached in client.guilds)
111
+ */
112
+ async fetchGuilds() {
113
+ const { Guild } = await import("./Guild-2P77HBQM.mjs");
114
+ const data = await this.client.rest.get(Routes2.currentUserGuilds());
115
+ const list = Array.isArray(data) ? data : data?.guilds ?? [];
116
+ const guilds = [];
117
+ for (const g of list) {
118
+ const guild = new Guild(this.client, g);
119
+ this.client.guilds.set(guild.id, guild);
120
+ guilds.push(guild);
121
+ }
122
+ return guilds;
123
+ }
124
+ /**
125
+ * Leave a guild. Requires the bot to be a member.
126
+ * @param guildId - The guild ID to leave
127
+ */
128
+ async leaveGuild(guildId) {
129
+ await this.client.rest.delete(Routes2.leaveGuild(guildId), { auth: true });
130
+ this.client.guilds.delete(guildId);
131
+ }
81
132
  };
82
133
 
83
134
  export {
@@ -0,0 +1,392 @@
1
+ import {
2
+ Events
3
+ } from "./chunk-AH7KYH2Z.mjs";
4
+ import {
5
+ buildSendBody
6
+ } from "./chunk-PM2IUGNR.mjs";
7
+ import {
8
+ Base
9
+ } from "./chunk-XNS4O6QJ.mjs";
10
+
11
+ // src/client/MessageManager.ts
12
+ var MessageManager = class {
13
+ constructor(client, channelId) {
14
+ this.client = client;
15
+ this.channelId = channelId;
16
+ }
17
+ /**
18
+ * Fetch a message by ID from this channel.
19
+ * @param messageId - Snowflake of the message
20
+ * @returns The message
21
+ * @throws FluxerError with MESSAGE_NOT_FOUND if the message does not exist
22
+ */
23
+ async fetch(messageId) {
24
+ return this.client.channels.fetchMessage(this.channelId, messageId);
25
+ }
26
+ };
27
+
28
+ // src/util/MessageCollector.ts
29
+ import { EventEmitter } from "events";
30
+ import { Collection } from "@fluxerjs/collection";
31
+ var MessageCollector = class extends EventEmitter {
32
+ client;
33
+ channelId;
34
+ options;
35
+ collected = new Collection();
36
+ _timeout = null;
37
+ _ended = false;
38
+ _listener;
39
+ constructor(client, channelId, options = {}) {
40
+ super();
41
+ this.client = client;
42
+ this.channelId = channelId;
43
+ this.options = {
44
+ filter: options.filter ?? (() => true),
45
+ time: options.time ?? 0,
46
+ max: options.max ?? 0
47
+ };
48
+ this._listener = (message) => {
49
+ if (this._ended || message.channelId !== this.channelId) return;
50
+ if (!this.options.filter(message)) return;
51
+ this.collected.set(message.id, message);
52
+ this.emit("collect", message);
53
+ if (this.options.max > 0 && this.collected.size >= this.options.max) {
54
+ this.stop("limit");
55
+ }
56
+ };
57
+ this.client.on(Events.MessageCreate, this._listener);
58
+ if (this.options.time > 0) {
59
+ this._timeout = setTimeout(() => this.stop("time"), this.options.time);
60
+ }
61
+ }
62
+ stop(reason = "user") {
63
+ if (this._ended) return;
64
+ this._ended = true;
65
+ this.client.off(Events.MessageCreate, this._listener);
66
+ if (this._timeout) {
67
+ clearTimeout(this._timeout);
68
+ this._timeout = null;
69
+ }
70
+ this.emit("end", this.collected, reason);
71
+ }
72
+ on(event, listener) {
73
+ return super.on(event, listener);
74
+ }
75
+ emit(event, ...args) {
76
+ return super.emit(event, ...args);
77
+ }
78
+ };
79
+
80
+ // src/structures/Channel.ts
81
+ import { ChannelType, Routes } from "@fluxerjs/types";
82
+ import { emitDeprecationWarning } from "@fluxerjs/util";
83
+ var Channel = class _Channel extends Base {
84
+ /** Whether this channel has a send method (TextChannel, DMChannel). */
85
+ isSendable() {
86
+ return "send" in this;
87
+ }
88
+ /** Whether this channel is a DM or Group DM. */
89
+ isDM() {
90
+ return this.type === ChannelType.DM || this.type === ChannelType.GroupDM;
91
+ }
92
+ /** Whether this channel is voice-based (VoiceChannel). */
93
+ isVoice() {
94
+ return "bitrate" in this;
95
+ }
96
+ /** Create a DM channel from API data (type DM or GroupDM). */
97
+ static createDM(client, data) {
98
+ return new DMChannel(client, data);
99
+ }
100
+ client;
101
+ id;
102
+ type;
103
+ /** Channel name. Guild channels and Group DMs have names; 1:1 DMs are typically null. */
104
+ name;
105
+ /** Channel icon hash (Group DMs). Null if none. */
106
+ icon;
107
+ /** ISO timestamp when the last message was pinned. Null if never pinned. */
108
+ lastPinTimestamp;
109
+ /** @param data - API channel from GET /channels/{id} or GET /guilds/{id}/channels */
110
+ constructor(client, data) {
111
+ super();
112
+ this.client = client;
113
+ this.id = data.id;
114
+ this.type = data.type;
115
+ this.name = data.name ?? null;
116
+ this.icon = data.icon ?? null;
117
+ this.lastPinTimestamp = data.last_pin_timestamp ?? null;
118
+ }
119
+ /**
120
+ * Create the appropriate channel subclass from API data.
121
+ * @param client - The client instance
122
+ * @param data - Channel data from the API
123
+ */
124
+ static from(client, data) {
125
+ const type = data.type ?? 0;
126
+ if (type === ChannelType.GuildText) return new TextChannel(client, data);
127
+ if (type === ChannelType.GuildCategory) return new CategoryChannel(client, data);
128
+ if (type === ChannelType.GuildVoice) return new VoiceChannel(client, data);
129
+ if (type === ChannelType.GuildLink || type === ChannelType.GuildLinkExtended)
130
+ return new LinkChannel(client, data);
131
+ return new GuildChannel(client, data);
132
+ }
133
+ /**
134
+ * Create a channel from API data, including DM and GroupDM.
135
+ * Used by ChannelManager.fetch() for GET /channels/{id}.
136
+ */
137
+ static fromOrCreate(client, data) {
138
+ const type = data.type ?? 0;
139
+ if (type === ChannelType.DM || type === ChannelType.GroupDM)
140
+ return _Channel.createDM(client, data);
141
+ return _Channel.from(client, data);
142
+ }
143
+ /**
144
+ * Bulk delete messages. Requires Manage Messages permission.
145
+ * @param messageIds - Array of message IDs to delete (2–100)
146
+ */
147
+ async bulkDeleteMessages(messageIds) {
148
+ await this.client.rest.post(Routes.channelBulkDelete(this.id), {
149
+ body: { message_ids: messageIds },
150
+ auth: true
151
+ });
152
+ }
153
+ /**
154
+ * Send a typing indicator to the channel. Lasts ~10 seconds.
155
+ */
156
+ async sendTyping() {
157
+ await this.client.rest.post(Routes.channelTyping(this.id), { auth: true });
158
+ }
159
+ };
160
+ var GuildChannel = class extends Channel {
161
+ guildId;
162
+ name;
163
+ position;
164
+ parentId;
165
+ /** Permission overwrites for roles and members. */
166
+ permissionOverwrites;
167
+ constructor(client, data) {
168
+ super(client, data);
169
+ this.guildId = data.guild_id ?? "";
170
+ this.name = data.name ?? null;
171
+ this.position = data.position;
172
+ this.parentId = data.parent_id ?? null;
173
+ this.permissionOverwrites = data.permission_overwrites ?? [];
174
+ }
175
+ /**
176
+ * Create a webhook in this channel.
177
+ * @param options - Webhook name and optional avatar URL
178
+ * @returns The webhook with token (required for send()). Requires Manage Webhooks permission.
179
+ */
180
+ async createWebhook(options) {
181
+ const { Webhook } = await import("./Webhook-RWDDYW2Q.mjs");
182
+ const data = await this.client.rest.post(Routes.channelWebhooks(this.id), {
183
+ body: options,
184
+ auth: true
185
+ });
186
+ return new Webhook(this.client, data);
187
+ }
188
+ /**
189
+ * Fetch all webhooks in this channel.
190
+ * @returns Webhooks (includes token when listing from channel; can send via send())
191
+ */
192
+ async fetchWebhooks() {
193
+ const { Webhook } = await import("./Webhook-RWDDYW2Q.mjs");
194
+ const data = await this.client.rest.get(Routes.channelWebhooks(this.id));
195
+ const list = Array.isArray(data) ? data : Object.values(data ?? {});
196
+ return list.map((w) => new Webhook(this.client, w));
197
+ }
198
+ /**
199
+ * Create an invite for this channel.
200
+ * @param options - max_uses (0–100), max_age (0–604800 seconds), unique, temporary
201
+ * Requires Create Instant Invite permission.
202
+ */
203
+ async createInvite(options) {
204
+ const { Invite } = await import("./Invite-UM5BU5A6.mjs");
205
+ const body = {};
206
+ if (options?.max_uses != null) body.max_uses = options.max_uses;
207
+ if (options?.max_age != null) body.max_age = options.max_age;
208
+ if (options?.unique != null) body.unique = options.unique;
209
+ if (options?.temporary != null) body.temporary = options.temporary;
210
+ const data = await this.client.rest.post(Routes.channelInvites(this.id), {
211
+ body: Object.keys(body).length ? body : void 0,
212
+ auth: true
213
+ });
214
+ return new Invite(this.client, data);
215
+ }
216
+ /**
217
+ * Fetch invites for this channel.
218
+ * Requires Manage Channel permission.
219
+ */
220
+ async fetchInvites() {
221
+ const { Invite } = await import("./Invite-UM5BU5A6.mjs");
222
+ const data = await this.client.rest.get(Routes.channelInvites(this.id));
223
+ const list = Array.isArray(data) ? data : Object.values(data ?? {});
224
+ return list.map((i) => new Invite(this.client, i));
225
+ }
226
+ };
227
+ var TextChannel = class extends GuildChannel {
228
+ topic;
229
+ nsfw;
230
+ rateLimitPerUser;
231
+ lastMessageId;
232
+ constructor(client, data) {
233
+ super(client, data);
234
+ this.topic = data.topic ?? null;
235
+ this.nsfw = data.nsfw ?? false;
236
+ this.rateLimitPerUser = data.rate_limit_per_user ?? 0;
237
+ this.lastMessageId = data.last_message_id ?? null;
238
+ }
239
+ /**
240
+ * Send a message to this channel.
241
+ * @param options - Text content or object with content, embeds, and/or files
242
+ */
243
+ async send(options) {
244
+ const opts = typeof options === "string" ? { content: options } : options;
245
+ const body = buildSendBody(options);
246
+ const { Message } = await import("./Message-OFIVTTAZ.mjs");
247
+ const postOptions = opts.files?.length ? { body, files: opts.files } : { body };
248
+ const data = await this.client.rest.post(Routes.channelMessages(this.id), postOptions);
249
+ return new Message(this.client, data);
250
+ }
251
+ /** Message manager for this channel. Use channel.messages.fetch(messageId). */
252
+ get messages() {
253
+ return new MessageManager(this.client, this.id);
254
+ }
255
+ /**
256
+ * Create a message collector for this channel.
257
+ * Collects messages matching the filter until time expires or max is reached.
258
+ * @param options - Filter, time (ms), and max count
259
+ * @example
260
+ * const collector = channel.createMessageCollector({ filter: m => m.author.id === userId, time: 10000 });
261
+ * collector.on('collect', m => console.log(m.content));
262
+ * collector.on('end', (collected, reason) => { ... });
263
+ */
264
+ createMessageCollector(options) {
265
+ return new MessageCollector(this.client, this.id, options);
266
+ }
267
+ /**
268
+ * Fetch pinned messages in this channel.
269
+ * @returns Pinned messages
270
+ */
271
+ async fetchPinnedMessages() {
272
+ const { Message } = await import("./Message-OFIVTTAZ.mjs");
273
+ const data = await this.client.rest.get(Routes.channelPins(this.id));
274
+ const list = Array.isArray(data) ? data : data?.items ?? [];
275
+ return list.map((item) => {
276
+ const msg = typeof item === "object" && item && "message" in item ? item.message : item;
277
+ return new Message(this.client, msg);
278
+ });
279
+ }
280
+ /**
281
+ * Fetch a message by ID from this channel.
282
+ * @param messageId - Snowflake of the message
283
+ * @returns The message, or null if not found
284
+ * @deprecated Use channel.messages.fetch(messageId) instead.
285
+ */
286
+ async fetchMessage(messageId) {
287
+ emitDeprecationWarning(
288
+ "Channel.fetchMessage()",
289
+ "Use channel.messages.fetch(messageId) instead."
290
+ );
291
+ return this.client.channels.fetchMessage(this.id, messageId);
292
+ }
293
+ };
294
+ var CategoryChannel = class extends GuildChannel {
295
+ };
296
+ var VoiceChannel = class extends GuildChannel {
297
+ bitrate;
298
+ userLimit;
299
+ rtcRegion;
300
+ constructor(client, data) {
301
+ super(client, data);
302
+ this.bitrate = data.bitrate ?? null;
303
+ this.userLimit = data.user_limit ?? null;
304
+ this.rtcRegion = data.rtc_region ?? null;
305
+ }
306
+ };
307
+ var LinkChannel = class extends GuildChannel {
308
+ url;
309
+ constructor(client, data) {
310
+ super(client, data);
311
+ this.url = data.url ?? null;
312
+ }
313
+ };
314
+ var DMChannel = class extends Channel {
315
+ lastMessageId;
316
+ /** Group DM creator ID. Null for 1:1 DMs. */
317
+ ownerId;
318
+ /** Group DM recipients as User objects. Empty for 1:1 DMs. */
319
+ recipients;
320
+ /** Group DM member display names (userId -> nickname). */
321
+ nicks;
322
+ constructor(client, data) {
323
+ super(client, data);
324
+ this.lastMessageId = data.last_message_id ?? null;
325
+ this.ownerId = data.owner_id ?? null;
326
+ this.recipients = (data.recipients ?? []).map(
327
+ (u) => client.getOrCreateUser(u)
328
+ );
329
+ this.nicks = data.nicks ?? {};
330
+ }
331
+ /**
332
+ * Send a message to this DM channel.
333
+ * @param options - Text content or object with content, embeds, and/or files
334
+ */
335
+ async send(options) {
336
+ const opts = typeof options === "string" ? { content: options } : options;
337
+ const body = buildSendBody(options);
338
+ const { Message } = await import("./Message-OFIVTTAZ.mjs");
339
+ const postOptions = opts.files?.length ? { body, files: opts.files } : { body };
340
+ const data = await this.client.rest.post(Routes.channelMessages(this.id), postOptions);
341
+ return new Message(this.client, data);
342
+ }
343
+ /** Message manager for this channel. Use channel.messages.fetch(messageId). */
344
+ get messages() {
345
+ return new MessageManager(this.client, this.id);
346
+ }
347
+ /**
348
+ * Create a message collector for this DM channel.
349
+ * @param options - Filter, time (ms), and max count
350
+ */
351
+ createMessageCollector(options) {
352
+ return new MessageCollector(this.client, this.id, options);
353
+ }
354
+ /**
355
+ * Fetch pinned messages in this DM channel.
356
+ * @returns Pinned messages
357
+ */
358
+ async fetchPinnedMessages() {
359
+ const { Message } = await import("./Message-OFIVTTAZ.mjs");
360
+ const data = await this.client.rest.get(Routes.channelPins(this.id));
361
+ const list = Array.isArray(data) ? data : data?.items ?? [];
362
+ return list.map((item) => {
363
+ const msg = typeof item === "object" && item && "message" in item ? item.message : item;
364
+ return new Message(this.client, msg);
365
+ });
366
+ }
367
+ /**
368
+ * Fetch a message by ID from this DM channel.
369
+ * @param messageId - Snowflake of the message
370
+ * @returns The message, or null if not found
371
+ * @deprecated Use channel.messages.fetch(messageId) instead.
372
+ */
373
+ async fetchMessage(messageId) {
374
+ emitDeprecationWarning(
375
+ "Channel.fetchMessage()",
376
+ "Use channel.messages.fetch(messageId) instead."
377
+ );
378
+ return this.client.channels.fetchMessage(this.id, messageId);
379
+ }
380
+ };
381
+
382
+ export {
383
+ MessageManager,
384
+ MessageCollector,
385
+ Channel,
386
+ GuildChannel,
387
+ TextChannel,
388
+ CategoryChannel,
389
+ VoiceChannel,
390
+ LinkChannel,
391
+ DMChannel
392
+ };
@@ -0,0 +1,29 @@
1
+ // src/util/messageUtils.ts
2
+ import { EmbedBuilder } from "@fluxerjs/builders";
3
+ function buildSendBody(options) {
4
+ const body = typeof options === "string" ? { content: options } : options;
5
+ const result = {};
6
+ if (body.content !== void 0) result.content = body.content;
7
+ if (body.embeds?.length) {
8
+ result.embeds = body.embeds.map((e) => e instanceof EmbedBuilder ? e.toJSON() : e);
9
+ }
10
+ if (body.files?.length && body.attachments) {
11
+ result.attachments = body.attachments.map((a) => ({
12
+ id: a.id,
13
+ filename: a.filename,
14
+ ...a.title != null && { title: a.title },
15
+ ...a.description != null && { description: a.description },
16
+ ...a.flags != null && { flags: a.flags }
17
+ }));
18
+ } else if (body.files?.length) {
19
+ result.attachments = body.files.map((f, i) => ({
20
+ id: i,
21
+ filename: f.filename ?? f.name
22
+ }));
23
+ }
24
+ return result;
25
+ }
26
+
27
+ export {
28
+ buildSendBody
29
+ };