@stoatx/client 0.3.0 → 0.5.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.
package/dist/index.js CHANGED
@@ -57,7 +57,7 @@ var Attachment = class extends Base {
57
57
  serverId;
58
58
  objectId;
59
59
  constructor(client, data) {
60
- super(client, { ...data, id: data._id });
60
+ super(client, { ...data, _id: data._id });
61
61
  this.id = data._id;
62
62
  this.tag = data.tag;
63
63
  this.filename = data.filename;
@@ -398,7 +398,7 @@ var Message = class extends Base {
398
398
  flags = 0;
399
399
  interactions = null;
400
400
  masquerade = null;
401
- mentions = [];
401
+ mentions = null;
402
402
  pinned = false;
403
403
  reactions = {};
404
404
  replies = [];
@@ -573,7 +573,7 @@ var Message = class extends Base {
573
573
  }
574
574
  _patch(data) {
575
575
  if (data.content !== void 0) this.content = data.content;
576
- if (data.edited !== void 0) this.editedAt = new Date(data.edited);
576
+ if (data.edited !== void 0) this.editedAt = new Date(data.edited ?? 0);
577
577
  if (data.pinned !== void 0) this.pinned = data.pinned;
578
578
  if (data.embeds !== void 0) this.embeds = data.embeds;
579
579
  if (data.flags !== void 0) this.flags = data.flags;
@@ -606,24 +606,6 @@ var Message = class extends Base {
606
606
  };
607
607
 
608
608
  // src/structures/User.ts
609
- var UserRelationship = /* @__PURE__ */ ((UserRelationship2) => {
610
- UserRelationship2["None"] = "None";
611
- UserRelationship2["User"] = "User";
612
- UserRelationship2["Friend"] = "Friend";
613
- UserRelationship2["Outgoing"] = "Outgoing";
614
- UserRelationship2["Incoming"] = "Incoming";
615
- UserRelationship2["Blocked"] = "Blocked";
616
- UserRelationship2["BlockedOther"] = "BlockedOther";
617
- return UserRelationship2;
618
- })(UserRelationship || {});
619
- var UserPresence = /* @__PURE__ */ ((UserPresence2) => {
620
- UserPresence2["Online"] = "Online";
621
- UserPresence2["Idle"] = "Idle";
622
- UserPresence2["Focus"] = "Focus";
623
- UserPresence2["Busy"] = "Busy";
624
- UserPresence2["Invisible"] = "Invisible";
625
- return UserPresence2;
626
- })(UserPresence || {});
627
609
  var User = class extends Base {
628
610
  discriminator;
629
611
  online;
@@ -657,7 +639,7 @@ var User = class extends Base {
657
639
  this.bot = data.bot ? { owner: data.bot.owner } : false;
658
640
  }
659
641
  if (data.avatar !== void 0) {
660
- this.avatar = new Attachment(this.client, data.avatar);
642
+ this.avatar = data.avatar ? new Attachment(this.client, data.avatar) : null;
661
643
  }
662
644
  if (clear && Array.isArray(clear)) {
663
645
  for (const field of clear) {
@@ -737,6 +719,7 @@ var GatewayManager = class {
737
719
  handleMessage(rawData) {
738
720
  const payload = JSON.parse(rawData.toString());
739
721
  const eventType = payload.type;
722
+ this.client.emit("raw", payload);
740
723
  switch (eventType) {
741
724
  case "Error":
742
725
  this.client.emit("error", new Error(`Gateway Error: ${payload.error || JSON.stringify(payload)}`));
@@ -814,7 +797,7 @@ var GatewayManager = class {
814
797
  const message = channel?.messages.cache.get(payload.id);
815
798
  if (message && payload.append.embeds) {
816
799
  const oldMessage = message._clone();
817
- message.embeds.push(...payload.append.embeds);
800
+ message.embeds = [...message.embeds || [], ...payload.append.embeds];
818
801
  this.client.emit("messageUpdate", oldMessage, message);
819
802
  }
820
803
  break;
@@ -954,13 +937,28 @@ var GatewayManager = class {
954
937
  }
955
938
  case "ServerMemberLeave": {
956
939
  const server = this.client.servers.cache.get(payload.id);
940
+ let member = null;
957
941
  if (server) {
958
- const member = server.members.cache.get(payload.user);
942
+ member = server.members.cache.get(payload.user);
959
943
  if (member) {
960
944
  server.members.cache.delete(payload.user);
961
- this.client.emit("serverMemberLeave", member);
962
945
  }
963
946
  }
947
+ const emitData = member || { serverId: payload.id, userId: payload.user };
948
+ if (payload.reason === "Ban") {
949
+ if (server) {
950
+ const dummyBanPayload = {
951
+ id: payload.user,
952
+ reason: null
953
+ };
954
+ server.bans._add(dummyBanPayload);
955
+ }
956
+ this.client.emit("serverBanAdd", emitData);
957
+ } else if (payload.reason === "Kick") {
958
+ this.client.emit("serverMemberKick", emitData);
959
+ } else {
960
+ this.client.emit("serverMemberLeave", emitData);
961
+ }
964
962
  break;
965
963
  }
966
964
  case "EmojiCreate": {
@@ -994,7 +992,8 @@ var GatewayManager = class {
994
992
  break;
995
993
  }
996
994
  default:
997
- this.client.emit("raw", payload);
995
+ this.client.emit("debug", `Unhandled Gateway Event Type: ${eventType}`);
996
+ break;
998
997
  }
999
998
  }
1000
999
  startPingLoop() {
@@ -1040,6 +1039,96 @@ var GatewayManager = class {
1040
1039
 
1041
1040
  // src/rest/RESTManager.ts
1042
1041
  import { request } from "undici";
1042
+
1043
+ // src/utils/schema.ts
1044
+ var queryParams = {
1045
+ "/": { get: [] },
1046
+ "/users/@me": { get: [] },
1047
+ "/users/{target}": { get: [], patch: [] },
1048
+ "/users/{target}/flags": { get: [] },
1049
+ "/users/@me/username": { patch: [] },
1050
+ "/users/{target}/default_avatar": { get: [] },
1051
+ "/users/{target}/profile": { get: [] },
1052
+ "/users/dms": { get: [] },
1053
+ "/users/{target}/dm": { get: [] },
1054
+ "/users/{target}/mutual": { get: [] },
1055
+ "/users/{target}/friend": { put: [], delete: [] },
1056
+ "/users/{target}/block": { put: [], delete: [] },
1057
+ "/users/friend": { post: [] },
1058
+ "/bots/create": { post: [] },
1059
+ "/bots/{target}/invite": { get: [], post: [] },
1060
+ "/bots/{bot_id}": { get: [], delete: [], patch: [] },
1061
+ "/bots/@me": { get: [] },
1062
+ "/channels/{target}/ack/{message}": { put: [] },
1063
+ "/channels/{target}": { get: [], delete: ["leave_silently"], patch: [] },
1064
+ "/channels/{target}/members": { get: [] },
1065
+ "/channels/{target}/invites": { post: [] },
1066
+ "/channels/{target}/messages": { get: ["limit", "before", "after", "sort", "nearby", "include_users"], post: [] },
1067
+ "/channels/{target}/search": { post: [] },
1068
+ "/channels/{target}/messages/{msg}/pin": { post: [], delete: [] },
1069
+ "/channels/{target}/messages/{msg}": { get: [], delete: [], patch: [] },
1070
+ "/channels/{target}/messages/bulk": { delete: [] },
1071
+ "/channels/create": { post: [] },
1072
+ "/channels/{group_id}/recipients/{member_id}": { put: [], delete: [] },
1073
+ "/channels/{target}/join_call": { post: [] },
1074
+ "/channels/{target}/end_ring/{target_user}": { put: [] },
1075
+ "/channels/{target}/permissions/{role_id}": { put: [] },
1076
+ "/channels/{target}/permissions/default": { put: [] },
1077
+ "/channels/{target}/messages/{msg}/reactions/{emoji}": { put: [], delete: ["user_id", "remove_all"] },
1078
+ "/channels/{target}/messages/{msg}/reactions": { delete: [] },
1079
+ "/channels/{channel_id}/webhooks": { get: [], post: [] },
1080
+ "/servers/create": { post: [] },
1081
+ "/servers/{target}": { get: ["include_channels"], delete: ["leave_silently"], patch: [] },
1082
+ "/servers/{target}/ack": { put: [] },
1083
+ "/servers/{server}/channels": { post: [] },
1084
+ "/servers/{target}/members": { get: ["exclude_offline"] },
1085
+ "/servers/{server_id}/members/{member_id}": { get: ["roles"], delete: [], patch: [] },
1086
+ "/servers/{target}/members_experimental_query": { get: ["query", "experimental_api"] },
1087
+ "/servers/{server}/bans/{target}": { put: [], delete: [] },
1088
+ "/servers/{target}/bans": { get: [] },
1089
+ "/servers/{target}/invites": { get: [] },
1090
+ "/servers/{target}/roles": { post: [] },
1091
+ "/servers/{target}/roles/{role_id}": { get: [], delete: [], patch: [] },
1092
+ "/servers/{target}/permissions/{role_id}": { put: [] },
1093
+ "/servers/{target}/permissions/default": { put: [] },
1094
+ "/servers/{target}/emojis": { get: [] },
1095
+ "/servers/{target}/roles/ranks": { patch: [] },
1096
+ "/invites/{target}": { get: [], post: [], delete: [] },
1097
+ "/custom/emoji/{emoji_id}": { get: [], put: [], delete: [], patch: [] },
1098
+ "/safety/report": { post: [] },
1099
+ "/auth/account/create": { post: [] },
1100
+ "/auth/account/reverify": { post: [] },
1101
+ "/auth/account/delete": { put: [], post: [] },
1102
+ "/auth/account/": { get: [] },
1103
+ "/auth/account/disable": { post: [] },
1104
+ "/auth/account/change/password": { patch: [] },
1105
+ "/auth/account/change/email": { patch: [] },
1106
+ "/auth/account/verify/{code}": { post: [] },
1107
+ "/auth/account/reset_password": { post: [], patch: [] },
1108
+ "/auth/session/login": { post: [] },
1109
+ "/auth/session/logout": { post: [] },
1110
+ "/auth/session/all": { get: [], delete: ["revoke_self"] },
1111
+ "/auth/session/{id}": { delete: [], patch: [] },
1112
+ "/auth/mfa/ticket": { put: [] },
1113
+ "/auth/mfa/": { get: [] },
1114
+ "/auth/mfa/recovery": { post: [], patch: [] },
1115
+ "/auth/mfa/methods": { get: [] },
1116
+ "/auth/mfa/totp": { put: [], post: [], delete: [] },
1117
+ "/onboard/hello": { get: [] },
1118
+ "/onboard/complete": { post: [] },
1119
+ "/policy/acknowledge": { post: [] },
1120
+ "/push/subscribe": { post: [] },
1121
+ "/push/unsubscribe": { post: [] },
1122
+ "/sync/settings/fetch": { post: [] },
1123
+ "/sync/settings/set": { post: ["timestamp"] },
1124
+ "/sync/unreads": { get: [] },
1125
+ "/webhooks/{webhook_id}/{token}/{message_id}": { delete: [], patch: [] },
1126
+ "/webhooks/{webhook_id}/{token}": { get: [], post: [], delete: [], patch: [] },
1127
+ "/webhooks/{webhook_id}": { get: [], delete: [], patch: [] },
1128
+ "/webhooks/{webhook_id}/{token}/github": { post: [] }
1129
+ };
1130
+
1131
+ // src/rest/RESTManager.ts
1043
1132
  var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1044
1133
  var AsyncBucket = class {
1045
1134
  remaining = 1;
@@ -1086,9 +1175,25 @@ var StoatAPIError = class _StoatAPIError extends Error {
1086
1175
  Object.setPrototypeOf(this, _StoatAPIError.prototype);
1087
1176
  }
1088
1177
  };
1178
+ var ALL_QUERY_KEYS = /* @__PURE__ */ new Set();
1179
+ for (const routes of Object.values(queryParams)) {
1180
+ for (const keys of Object.values(routes)) {
1181
+ for (const key of keys) {
1182
+ ALL_QUERY_KEYS.add(key);
1183
+ }
1184
+ }
1185
+ }
1089
1186
  var RESTManager = class {
1090
1187
  constructor(client) {
1091
1188
  this.client = client;
1189
+ setInterval(() => {
1190
+ const now = Date.now();
1191
+ for (const [key, bucket] of this.buckets.entries()) {
1192
+ if (now > bucket.resetAt && bucket.remaining > 0) {
1193
+ this.buckets.delete(key);
1194
+ }
1195
+ }
1196
+ }, 3e5).unref();
1092
1197
  }
1093
1198
  baseURL = "https://stoat.chat/api";
1094
1199
  token = null;
@@ -1102,17 +1207,35 @@ var RESTManager = class {
1102
1207
  getRouteKey(method, endpoint) {
1103
1208
  return `${method}:${endpoint}`;
1104
1209
  }
1105
- makeRequest(method, endpoint, body) {
1106
- const routeKey = this.getRouteKey(method, endpoint);
1107
- let bucket = this.buckets.get(routeKey);
1108
- if (!bucket) {
1109
- bucket = new AsyncBucket();
1110
- this.buckets.set(routeKey, bucket);
1210
+ makeRequest(method, endpoint, params) {
1211
+ let finalEndpoint = endpoint;
1212
+ let finalBody = void 0;
1213
+ if (params && typeof params === "object") {
1214
+ const query = new URLSearchParams();
1215
+ finalBody = {};
1216
+ for (const [key, value] of Object.entries(params)) {
1217
+ if (value !== void 0) {
1218
+ if (ALL_QUERY_KEYS.has(key)) {
1219
+ query.append(key, String(value));
1220
+ } else {
1221
+ finalBody[key] = value;
1222
+ }
1223
+ }
1224
+ }
1225
+ const qs = query.toString();
1226
+ if (qs) finalEndpoint += `?${qs}`;
1227
+ if (Object.keys(finalBody).length === 0) finalBody = void 0;
1111
1228
  }
1229
+ const routeKey = this.getRouteKey(method, finalEndpoint);
1112
1230
  return new Promise((resolve, reject) => {
1231
+ let bucket = this.buckets.get(routeKey);
1232
+ if (!bucket) {
1233
+ bucket = new AsyncBucket();
1234
+ this.buckets.set(routeKey, bucket);
1235
+ }
1113
1236
  bucket.queue = bucket.queue.then(async () => {
1114
1237
  try {
1115
- const result = await this.execute(method, endpoint, body, bucket);
1238
+ const result = await this.execute(method, finalEndpoint, finalBody, bucket);
1116
1239
  resolve(result);
1117
1240
  } catch (error) {
1118
1241
  reject(error);
@@ -1168,9 +1291,9 @@ var RESTManager = class {
1168
1291
  /**
1169
1292
  * Uploads a file to Stoat's CDN and returns the File ID
1170
1293
  */
1171
- async uploadFile(filename, fileBuffer) {
1294
+ async uploadFile(tag, fileBuffer, filename) {
1172
1295
  if (!this.token) throw new Error("REST_NOT_READY: No token available.");
1173
- const url = "https://cdn.stoatusercontent.com/attachments";
1296
+ const url = `https://cdn.stoatusercontent.com/${tag}`;
1174
1297
  const formData = new FormData();
1175
1298
  formData.append("file", new Blob([fileBuffer]), filename);
1176
1299
  const response = await fetch(url, {
@@ -1193,20 +1316,20 @@ var RESTManager = class {
1193
1316
  const data = await response.json();
1194
1317
  return data.id;
1195
1318
  }
1196
- get(endpoint) {
1197
- return this.makeRequest("GET", endpoint);
1319
+ get(endpoint, params) {
1320
+ return this.makeRequest("get", endpoint, params);
1198
1321
  }
1199
- post(endpoint, body) {
1200
- return this.makeRequest("POST", endpoint, body);
1322
+ post(endpoint, params) {
1323
+ return this.makeRequest("post", endpoint, params);
1201
1324
  }
1202
- patch(endpoint, body) {
1203
- return this.makeRequest("PATCH", endpoint, body);
1325
+ patch(endpoint, params) {
1326
+ return this.makeRequest("patch", endpoint, params);
1204
1327
  }
1205
- delete(endpoint, body) {
1206
- return this.makeRequest("DELETE", endpoint, body);
1328
+ delete(endpoint, params) {
1329
+ return this.makeRequest("delete", endpoint, params);
1207
1330
  }
1208
- async put(endpoint, body) {
1209
- return this.makeRequest("PUT", endpoint, body);
1331
+ put(endpoint, params) {
1332
+ return this.makeRequest("put", endpoint, params);
1210
1333
  }
1211
1334
  };
1212
1335
 
@@ -1238,6 +1361,42 @@ var BaseManager = class {
1238
1361
  }
1239
1362
  };
1240
1363
 
1364
+ // src/builders/AttachmentBuilder.ts
1365
+ var AttachmentBuilder = class {
1366
+ // Filename for CDN to use, optional but recommended
1367
+ filename = void 0;
1368
+ file;
1369
+ /**
1370
+ * Creates a new AttachmentBuilder with the given file and optional filename.
1371
+ * @param file The file data as a Buffer or Blob.
1372
+ * @param filename An optional filename to use for the uploaded file. If not provided, the CDN will assign a default name.
1373
+ * Providing a filename can help with organization and debugging, but is not strictly required.
1374
+ * @example
1375
+ * // Create an attachment from a Buffer with a custom filename
1376
+ * const buffer = Buffer.from("Hello, world!");
1377
+ * const attachment = new AttachmentBuilder(buffer, "greeting.txt");
1378
+ */
1379
+ constructor(file, filename) {
1380
+ this.filename = filename;
1381
+ this.file = file;
1382
+ }
1383
+ /**
1384
+ * Uploads this attachment to the Stoat CDN and returns the resulting file ID.
1385
+ * @internal — use `resolveAttachment()` instead of calling this directly.
1386
+ */
1387
+ async upload(rest, tag) {
1388
+ return rest.uploadFile(tag, this.file, this.filename);
1389
+ }
1390
+ };
1391
+
1392
+ // src/utils/resolveAttachment.ts
1393
+ async function resolveAttachment(rest, value, tag) {
1394
+ if (value instanceof AttachmentBuilder) {
1395
+ return value.upload(rest, tag);
1396
+ }
1397
+ return value;
1398
+ }
1399
+
1241
1400
  // src/managers/MessageManager.ts
1242
1401
  var MessageManager = class extends BaseManager {
1243
1402
  constructor(client, channel, limit = Infinity) {
@@ -1248,7 +1407,7 @@ var MessageManager = class extends BaseManager {
1248
1407
  * Tell BaseManager how to find the ID for Messages
1249
1408
  */
1250
1409
  extractId(data) {
1251
- return data._id ?? data.id;
1410
+ return data._id;
1252
1411
  }
1253
1412
  /**
1254
1413
  * Tell BaseManager how to build a Message
@@ -1273,20 +1432,31 @@ var MessageManager = class extends BaseManager {
1273
1432
  * const history = await channel.messages.fetchMany({ limit: 20, before: "01H..." });
1274
1433
  */
1275
1434
  async fetchMany(options = {}) {
1276
- const params = new URLSearchParams();
1277
- if (options.limit !== void 0) params.append("limit", options.limit.toString());
1278
- if (options.before !== void 0) params.append("before", options.before);
1279
- if (options.after !== void 0) params.append("after", options.after);
1280
- if (options.sort !== void 0) params.append("sort", options.sort);
1281
- if (options.nearby !== void 0) params.append("nearby", options.nearby);
1282
- if (options.includeUsers !== void 0) params.append("include_users", options.includeUsers.toString());
1283
- const queryString = params.toString();
1284
- const endpoint = `/channels/${this.channel.id}/messages${queryString ? `?${queryString}` : ""}`;
1285
- const data = await this.client.rest.get(endpoint);
1286
- const rawMessages = Array.isArray(data) ? data : data.messages || [];
1287
- if (!Array.isArray(data) && data.users) {
1288
- for (const userData of data.users) {
1289
- this.client.users._add(userData);
1435
+ const endpoint = `/channels/${this.channel.id}/messages`;
1436
+ const query = {};
1437
+ if (options.limit !== void 0) query.limit = options.limit;
1438
+ if (options.before !== void 0) query.before = options.before;
1439
+ if (options.after !== void 0) query.after = options.after;
1440
+ if (options.sort !== void 0) query.sort = options.sort;
1441
+ if (options.nearby !== void 0) query.nearby = options.nearby;
1442
+ if (options.includeUsers !== void 0) query.include_users = options.includeUsers;
1443
+ const data = await this.client.rest.get(endpoint, query);
1444
+ let rawMessages;
1445
+ if (Array.isArray(data)) {
1446
+ rawMessages = data;
1447
+ } else {
1448
+ rawMessages = data.messages;
1449
+ if (data.users) {
1450
+ for (const userData of data.users) {
1451
+ this.client.users._add(userData);
1452
+ }
1453
+ }
1454
+ if (data.members && this.channel.isText()) {
1455
+ const serverId = this.channel.serverId;
1456
+ const server = await this.client.servers.fetch(serverId);
1457
+ for (const memberData of data.members) {
1458
+ server.members._add(memberData);
1459
+ }
1290
1460
  }
1291
1461
  }
1292
1462
  const fetched = new Collection();
@@ -1307,11 +1477,19 @@ var MessageManager = class extends BaseManager {
1307
1477
  * @returns A promise that resolves to the sent Message.
1308
1478
  */
1309
1479
  async send(contentOrOptions) {
1310
- const payload = typeof contentOrOptions === "string" ? { content: contentOrOptions } : { ...contentOrOptions };
1311
- if (payload.embeds) {
1312
- payload.embeds = payload.embeds.map(
1313
- (embed) => typeof embed.toJSON === "function" ? embed.toJSON() : embed
1480
+ const opts = typeof contentOrOptions === "string" ? { content: contentOrOptions } : contentOrOptions;
1481
+ const payload = {};
1482
+ if (opts.embeds && opts.embeds.length) {
1483
+ payload.embeds = opts.embeds.map((embed) => typeof embed.toJSON === "function" ? embed.toJSON() : embed);
1484
+ }
1485
+ if (opts.attachments && opts.attachments.length > 0) {
1486
+ const resolved = await Promise.all(
1487
+ opts.attachments.map((attachment) => resolveAttachment(this.client.rest, attachment, "attachments"))
1314
1488
  );
1489
+ const validAttachments = resolved.filter((id) => id !== void 0);
1490
+ if (validAttachments.length > 0) {
1491
+ payload.attachments = validAttachments;
1492
+ }
1315
1493
  }
1316
1494
  const data = await this.client.rest.post(`/channels/${this.channel.id}/messages`, payload);
1317
1495
  return new Message(this.client, data);
@@ -1324,19 +1502,20 @@ var MessageManager = class extends BaseManager {
1324
1502
  */
1325
1503
  async edit(message, contentOrOptions) {
1326
1504
  const id = this.resolveId(message);
1327
- const payload = typeof contentOrOptions === "string" ? { content: contentOrOptions } : { ...contentOrOptions };
1328
- if (payload.embeds) {
1329
- payload.embeds = payload.embeds.map(
1330
- (embed) => typeof embed.toJSON === "function" ? embed.toJSON() : embed
1331
- );
1505
+ const opts = typeof contentOrOptions === "string" ? { content: contentOrOptions } : contentOrOptions;
1506
+ const payload = {};
1507
+ if (opts.content !== void 0) {
1508
+ payload.content = opts.content;
1332
1509
  }
1333
- const data = await this.client.rest.patch(`/channels/${this.channel.id}/messages/${id}`, payload);
1334
- const existing = this.cache.get(id);
1335
- if (existing) {
1336
- existing._patch(data);
1337
- return existing;
1510
+ if (opts.embeds !== void 0) {
1511
+ if (opts.embeds === null) {
1512
+ payload.embeds = [];
1513
+ } else {
1514
+ payload.embeds = opts.embeds.map((embed) => "toJSON" in embed ? embed.toJSON() : embed);
1515
+ }
1338
1516
  }
1339
- return new Message(this.client, data);
1517
+ const data = await this.client.rest.patch(`/channels/${this.channel.id}/messages/${id}`, payload);
1518
+ return this._add(data);
1340
1519
  }
1341
1520
  /**
1342
1521
  * Deletes a message from the channel.
@@ -1353,7 +1532,7 @@ var MessageManager = class extends BaseManager {
1353
1532
  */
1354
1533
  async pin(message) {
1355
1534
  const id = this.resolveId(message);
1356
- await this.client.rest.post(`/channels/${this.channel.id}/messages/${id}/pin`, {});
1535
+ await this.client.rest.post(`/channels/${this.channel.id}/messages/${id}/pin`);
1357
1536
  const existing = this.cache.get(id);
1358
1537
  if (existing) existing.pinned = true;
1359
1538
  }
@@ -1399,12 +1578,14 @@ var MessageManager = class extends BaseManager {
1399
1578
  async removeReaction(message, reaction, userId, removeAll) {
1400
1579
  const id = this.resolveId(message);
1401
1580
  const targetUser = userId ? this.client.users.resolveId(userId) : void 0;
1402
- const params = new URLSearchParams();
1403
- if (targetUser) params.append("user_id", targetUser);
1404
- if (removeAll) params.append("remove_all", "true");
1405
- const queryString = params.toString();
1406
- const endpoint = `/channels/${this.channel.id}/messages/${id}/reactions/${encodeURIComponent(reaction)}${queryString ? `?${queryString}` : ""}`;
1407
- await this.client.rest.delete(endpoint);
1581
+ const endpoint = `/channels/${this.channel.id}/messages/${id}/reactions/${reaction}`;
1582
+ const query = {};
1583
+ if (targetUser) {
1584
+ query.user_id = targetUser;
1585
+ } else if (removeAll) {
1586
+ query.remove_all = true;
1587
+ }
1588
+ await this.client.rest.delete(endpoint, query);
1408
1589
  }
1409
1590
  /**
1410
1591
  * Remove all reactions from a message
@@ -1467,12 +1648,6 @@ var MessageCollector = class extends Collector {
1467
1648
  };
1468
1649
 
1469
1650
  // src/structures/BaseChannel.ts
1470
- var ChannelType = /* @__PURE__ */ ((ChannelType2) => {
1471
- ChannelType2["TEXT"] = "TextChannel";
1472
- ChannelType2["DM"] = "DirectMessage";
1473
- ChannelType2["GROUP"] = "Group";
1474
- return ChannelType2;
1475
- })(ChannelType || {});
1476
1651
  var BaseChannel = class extends Base {
1477
1652
  type;
1478
1653
  messages;
@@ -1596,13 +1771,13 @@ var BaseChannel = class extends Base {
1596
1771
  });
1597
1772
  }
1598
1773
  isText() {
1599
- return this.type === "TextChannel" /* TEXT */;
1774
+ return this.type === "TextChannel";
1600
1775
  }
1601
1776
  isDM() {
1602
- return this.type === "DirectMessage" /* DM */;
1777
+ return this.type === "DirectMessage";
1603
1778
  }
1604
1779
  isGroup() {
1605
- return this.type === "Group" /* GROUP */;
1780
+ return this.type === "Group";
1606
1781
  }
1607
1782
  };
1608
1783
 
@@ -1622,7 +1797,9 @@ var TextChannel = class extends BaseChannel {
1622
1797
  this.serverId = data.server;
1623
1798
  this.defaultPermissions = data.default_permissions;
1624
1799
  this.description = data.description;
1625
- this.icon = data.icon;
1800
+ if (data.icon !== void 0) {
1801
+ this.icon = data.icon ? new Attachment(this.client, data.icon) : null;
1802
+ }
1626
1803
  this.lastMessageId = data.last_message_id;
1627
1804
  this.nsfw = data.nsfw ?? false;
1628
1805
  this.slowmode = data.slowmode ?? 0;
@@ -1692,6 +1869,9 @@ var TextChannel = class extends BaseChannel {
1692
1869
  async setCategory(category) {
1693
1870
  const serverId = this.serverId;
1694
1871
  const server = await this.client.servers.fetch(serverId);
1872
+ if (!server.categories || server.categories.length === 0) {
1873
+ throw new Error("This server has no categories to move the channel into.");
1874
+ }
1695
1875
  const categories = server.categories.map((c) => ({
1696
1876
  id: c.id,
1697
1877
  title: c.title,
@@ -1722,6 +1902,9 @@ var TextChannel = class extends BaseChannel {
1722
1902
  async setPosition(position) {
1723
1903
  const serverId = this.serverId;
1724
1904
  const server = await this.client.servers.fetch(serverId);
1905
+ if (!server.categories || server.categories.length === 0) {
1906
+ throw new Error("This server has no categories to move the channel into.");
1907
+ }
1725
1908
  const categories = server.categories.map((c) => ({
1726
1909
  id: c.id,
1727
1910
  title: c.title,
@@ -1909,18 +2092,245 @@ var GroupChannel = class extends BaseChannel {
1909
2092
  // src/utils/ChannelFactory.ts
1910
2093
  function createChannel(client, data) {
1911
2094
  switch (data.channel_type) {
1912
- case "TextChannel" /* TEXT */:
2095
+ case "TextChannel":
1913
2096
  return new TextChannel(client, data);
1914
- case "DirectMessage" /* DM */:
2097
+ case "DirectMessage":
1915
2098
  return new DMChannel(client, data);
1916
- case "Group" /* GROUP */:
2099
+ case "Group":
1917
2100
  return new GroupChannel(client, data);
1918
2101
  default:
1919
- client.emit("debug", `Received unknown channel type: ${data.type}`);
2102
+ client.emit("debug", `Received unknown channel type: ${data.channel_type}`);
1920
2103
  return new UnknownChannel(client, data);
1921
2104
  }
1922
2105
  }
1923
2106
 
2107
+ // src/utils/BitField.ts
2108
+ var BitField = class _BitField {
2109
+ static Flags = {};
2110
+ static DefaultBit = 0;
2111
+ bitfield;
2112
+ constructor(bits) {
2113
+ this.bitfield = this.constructor.resolve(
2114
+ bits ?? this.constructor.DefaultBit
2115
+ );
2116
+ }
2117
+ /**
2118
+ * Checks whether this bitfield has any of the given bits set.
2119
+ *
2120
+ * @param bit The bit(s) to test against.
2121
+ * @returns `true` if at least one of the provided bits is set.
2122
+ *
2123
+ * @example
2124
+ * perms.any(['SendMessage', 'ManageChannel']); // true if either is set
2125
+ */
2126
+ any(bit) {
2127
+ const resolved = this.constructor.resolve(bit);
2128
+ if (typeof this.bitfield === "bigint" && typeof resolved === "bigint") {
2129
+ return (this.bitfield & resolved) !== BigInt(0);
2130
+ }
2131
+ return (Number(this.bitfield) & Number(resolved)) !== 0;
2132
+ }
2133
+ /**
2134
+ * Checks whether this bitfield is exactly equal to the given bit value.
2135
+ *
2136
+ * @param bit The bit(s) to compare against.
2137
+ * @returns `true` if the resolved bit value is identical to this bitfield.
2138
+ *
2139
+ * @example
2140
+ * new Permissions(0n).equals(0n); // true
2141
+ */
2142
+ equals(bit) {
2143
+ return this.bitfield === this.constructor.resolve(bit);
2144
+ }
2145
+ /**
2146
+ * Checks whether this bitfield has *all* of the given bits set.
2147
+ *
2148
+ * @param bit The bit(s) to check for.
2149
+ * @returns `true` if every provided bit is set in this bitfield.
2150
+ *
2151
+ * @example
2152
+ * perms.has('SendMessage');
2153
+ * perms.has(['SendMessage', 'ViewChannel']); // true only if both are set
2154
+ */
2155
+ has(bit, ..._hasParams) {
2156
+ const resolvedBit = this.constructor.resolve(bit);
2157
+ if (typeof this.bitfield === "bigint" && typeof resolvedBit === "bigint") {
2158
+ return (this.bitfield & resolvedBit) === resolvedBit;
2159
+ }
2160
+ return (Number(this.bitfield) & Number(resolvedBit)) === Number(resolvedBit);
2161
+ }
2162
+ /**
2163
+ * Returns the flag names present in `bits` that are *missing* from this bitfield.
2164
+ *
2165
+ * @param bits The bits to check against.
2166
+ * @returns An array of flag name strings that are in `bits` but not in this bitfield.
2167
+ *
2168
+ * @example
2169
+ * // If perms only has SendMessage:
2170
+ * perms.missing(['SendMessage', 'ManageChannel']); // ['ManageChannel']
2171
+ */
2172
+ missing(bits, ...hasParams) {
2173
+ return new this.constructor(bits).remove(this).toArray(...hasParams);
2174
+ }
2175
+ /**
2176
+ * Freezes this BitField instance, making it immutable.
2177
+ * Subsequent calls to `add()` or `remove()` will return a new instance instead of mutating this one.
2178
+ *
2179
+ * @returns This instance, frozen.
2180
+ */
2181
+ freeze() {
2182
+ return Object.freeze(this);
2183
+ }
2184
+ /**
2185
+ * Adds one or more bits to this bitfield.
2186
+ * If the instance is frozen, returns a new BitField with the bits added.
2187
+ *
2188
+ * @param bits The bit(s) to add.
2189
+ * @returns This instance (or a new one if frozen), with the bits added.
2190
+ *
2191
+ * @example
2192
+ * perms.add('SendMessage', 'ViewChannel');
2193
+ */
2194
+ add(...bits) {
2195
+ let total = this.constructor.DefaultBit;
2196
+ for (const bit of bits) {
2197
+ const resolved = this.constructor.resolve(bit);
2198
+ if (typeof total === "bigint" && typeof resolved === "bigint") {
2199
+ total |= resolved;
2200
+ } else {
2201
+ total = Number(total) | Number(resolved);
2202
+ }
2203
+ }
2204
+ if (typeof this.bitfield === "bigint" && typeof total === "bigint") {
2205
+ if (Object.isFrozen(this)) return new this.constructor(this.bitfield | total);
2206
+ this.bitfield |= total;
2207
+ } else {
2208
+ if (Object.isFrozen(this))
2209
+ return new this.constructor(Number(this.bitfield) | Number(total));
2210
+ this.bitfield = Number(this.bitfield) | Number(total);
2211
+ }
2212
+ return this;
2213
+ }
2214
+ /**
2215
+ * Removes one or more bits from this bitfield.
2216
+ * If the instance is frozen, returns a new BitField with the bits removed.
2217
+ *
2218
+ * @param bits The bit(s) to remove.
2219
+ * @returns This instance (or a new one if frozen), with the bits cleared.
2220
+ *
2221
+ * @example
2222
+ * perms.remove('ManageChannel');
2223
+ */
2224
+ remove(...bits) {
2225
+ let total = this.constructor.DefaultBit;
2226
+ for (const bit of bits) {
2227
+ const resolved = this.constructor.resolve(bit);
2228
+ if (typeof total === "bigint" && typeof resolved === "bigint") {
2229
+ total |= resolved;
2230
+ } else {
2231
+ total = Number(total) | Number(resolved);
2232
+ }
2233
+ }
2234
+ if (typeof this.bitfield === "bigint" && typeof total === "bigint") {
2235
+ if (Object.isFrozen(this)) return new this.constructor(this.bitfield & ~total);
2236
+ this.bitfield &= ~total;
2237
+ } else {
2238
+ if (Object.isFrozen(this))
2239
+ return new this.constructor(Number(this.bitfield) & ~Number(total));
2240
+ this.bitfield = Number(this.bitfield) & ~Number(total);
2241
+ }
2242
+ return this;
2243
+ }
2244
+ /**
2245
+ * Serializes this bitfield to a plain object mapping each flag name to a boolean
2246
+ * indicating whether that flag is set.
2247
+ *
2248
+ * @returns A record of `{ [flagName]: boolean }` for all defined flags.
2249
+ *
2250
+ * @example
2251
+ * perms.serialize();
2252
+ * // { SendMessage: true, ManageChannel: false, ... }
2253
+ */
2254
+ serialize(...hasParams) {
2255
+ const serialized = {};
2256
+ for (const [flag, bit] of Object.entries(this.constructor.Flags)) {
2257
+ if (isNaN(Number(flag))) serialized[flag] = this.has(bit, ...hasParams);
2258
+ }
2259
+ return serialized;
2260
+ }
2261
+ /**
2262
+ * Returns an array of flag names that are set in this bitfield.
2263
+ *
2264
+ * @returns An array of string flag names.
2265
+ *
2266
+ * @example
2267
+ * perms.toArray(); // ['SendMessage', 'ViewChannel']
2268
+ */
2269
+ toArray(...hasParams) {
2270
+ return [...this[Symbol.iterator](...hasParams)];
2271
+ }
2272
+ /**
2273
+ * Returns the bitfield value as a JSON-safe primitive.
2274
+ * Numbers are returned as-is; bigints are converted to their string representation
2275
+ * to avoid JSON serialization errors.
2276
+ */
2277
+ toJSON() {
2278
+ return typeof this.bitfield === "number" ? this.bitfield : this.bitfield.toString();
2279
+ }
2280
+ /**
2281
+ * Returns the underlying numeric value of this bitfield.
2282
+ * Allows BitField instances to be used directly in arithmetic expressions.
2283
+ */
2284
+ valueOf() {
2285
+ return this.bitfield;
2286
+ }
2287
+ /**
2288
+ * Iterates over the names of all flags that are set in this bitfield.
2289
+ *
2290
+ * @example
2291
+ * for (const flag of perms) {
2292
+ * console.log(flag); // 'SendMessage', 'ViewChannel', etc.
2293
+ * }
2294
+ */
2295
+ *[Symbol.iterator](...hasParams) {
2296
+ for (const bitName of Object.keys(this.constructor.Flags)) {
2297
+ if (isNaN(Number(bitName)) && this.has(bitName, ...hasParams)) yield bitName;
2298
+ }
2299
+ }
2300
+ /**
2301
+ * Resolves a {@link BitFieldResolvable} into a raw `number | bigint`.
2302
+ *
2303
+ * Resolution rules (in order):
2304
+ * - `undefined` → `DefaultBit`
2305
+ * - A number or bigint matching `DefaultBit`'s type and >= 0 → returned as-is
2306
+ * - A `BitField` instance → its `.bitfield` value
2307
+ * - An array → each element resolved and OR'd together
2308
+ * - A numeric string → parsed as `BigInt` or `Number` depending on `DefaultBit`'s type
2309
+ * - A named string flag → looked up in `Flags`
2310
+ * - Anything else → throws `RangeError`
2311
+ *
2312
+ * @param bit The value to resolve.
2313
+ * @throws {RangeError} If the value cannot be resolved to a valid bit.
2314
+ */
2315
+ static resolve(bit) {
2316
+ const { DefaultBit } = this;
2317
+ if (bit === void 0) return DefaultBit;
2318
+ if (typeof DefaultBit === typeof bit && bit >= DefaultBit) return bit;
2319
+ if (bit instanceof _BitField) return bit.bitfield;
2320
+ if (Array.isArray(bit)) {
2321
+ return bit.map((b) => this.resolve(b)).reduce((prev, b) => {
2322
+ if (typeof prev === "bigint" && typeof b === "bigint") return prev | b;
2323
+ return Number(prev) | Number(b);
2324
+ }, DefaultBit);
2325
+ }
2326
+ if (typeof bit === "string") {
2327
+ if (!isNaN(Number(bit))) return typeof DefaultBit === "bigint" ? BigInt(bit) : Number(bit);
2328
+ if (this.Flags[bit] !== void 0) return this.Flags[bit];
2329
+ }
2330
+ throw new RangeError(`Invalid bitfield flag or number: ${String(bit)}`);
2331
+ }
2332
+ };
2333
+
1924
2334
  // src/utils/permissions.ts
1925
2335
  var PermissionFlags = {
1926
2336
  // Server permissions
@@ -1964,26 +2374,26 @@ var PermissionFlags = {
1964
2374
  // Grant all
1965
2375
  GrantAllSafe: 0x000fffffffffffffn
1966
2376
  };
1967
- var Permissions = class {
1968
- /**
1969
- * Converts a string, BigInt, or array of strings into a single BigInt
1970
- */
1971
- static resolve(permission) {
1972
- if (typeof permission === "bigint") return permission;
1973
- if (typeof permission === "string") {
1974
- return PermissionFlags[permission] ?? 0n;
1975
- }
1976
- if (Array.isArray(permission)) {
1977
- return permission.reduce((acc, p) => acc | this.resolve(p), 0n);
1978
- }
1979
- return 0n;
2377
+ var Permissions = class extends BitField {
2378
+ static Flags = PermissionFlags;
2379
+ static DefaultBit = 0n;
2380
+ static resolve(bit) {
2381
+ return super.resolve(bit);
1980
2382
  }
1981
- /**
1982
- * Checks if a specific permission bit exists
1983
- */
1984
- static has(totalPermissions, permissionToCheck) {
1985
- const resolvedCheck = this.resolve(permissionToCheck);
1986
- return (totalPermissions & resolvedCheck) === resolvedCheck;
2383
+ has(bit) {
2384
+ return super.has(bit);
2385
+ }
2386
+ any(bit) {
2387
+ return super.any(bit);
2388
+ }
2389
+ missing(bits) {
2390
+ return super.missing(bits);
2391
+ }
2392
+ add(...bits) {
2393
+ return super.add(...bits);
2394
+ }
2395
+ remove(...bits) {
2396
+ return super.remove(...bits);
1987
2397
  }
1988
2398
  };
1989
2399
 
@@ -1998,7 +2408,7 @@ var ChannelManager = class extends BaseManager {
1998
2408
  super(client, limit);
1999
2409
  }
2000
2410
  extractId(data) {
2001
- return data._id ?? data.id;
2411
+ return data._id;
2002
2412
  }
2003
2413
  construct(data) {
2004
2414
  return createChannel(this.client, data);
@@ -2091,8 +2501,14 @@ var ChannelManager = class extends BaseManager {
2091
2501
  else payload.description = options.description;
2092
2502
  }
2093
2503
  if (options.icon !== void 0) {
2094
- if (options.icon === null) remove.push("Icon");
2095
- else payload.icon = options.icon;
2504
+ if (options.icon === null) {
2505
+ remove.push("Icon");
2506
+ } else {
2507
+ const resolvedIcon = await resolveAttachment(this.client.rest, options.icon, "icons");
2508
+ if (resolvedIcon !== void 0) {
2509
+ payload.icon = resolvedIcon;
2510
+ }
2511
+ }
2096
2512
  }
2097
2513
  if (remove.length > 0) payload.remove = remove;
2098
2514
  if (Object.keys(payload).length === 0) return this.fetch(channel);
@@ -2177,7 +2593,7 @@ var ChannelManager = class extends BaseManager {
2177
2593
  * await client.channels.pin("CHANNEL_ID", "MESSAGE_ID");
2178
2594
  */
2179
2595
  async pin(id, messageId) {
2180
- await this.client.rest.post(`/channels/${id}/pins/${messageId}`);
2596
+ await this.client.rest.post(`/channels/${id}/messages/${messageId}/pin`);
2181
2597
  }
2182
2598
  /**
2183
2599
  * Unpin a message
@@ -2207,7 +2623,7 @@ var ChannelManager = class extends BaseManager {
2207
2623
  if ("id" in msg) return msg.id;
2208
2624
  throw new TypeError("Invalid MessageResolvable provided. Expected a Message object or a string ID/Mention.");
2209
2625
  });
2210
- await this.client.rest.delete(`/channels/${id}/messages/bulk`, { messages: messageIds });
2626
+ await this.client.rest.delete(`/channels/${id}/messages/bulk`, { ids: messageIds });
2211
2627
  }
2212
2628
  };
2213
2629
 
@@ -2306,20 +2722,20 @@ var Member = class extends Base {
2306
2722
  canRecieve = false;
2307
2723
  // Member roles manager
2308
2724
  roles;
2309
- constructor(client, data) {
2310
- super(client, { _id: data.user._id });
2311
- this.serverId = data.serverId || data.server_id;
2312
- this.joinedAt = new Date(data.joinedAt || data.joined_at);
2725
+ constructor(client, data, serverId) {
2726
+ super(client, { _id: data._id?.user });
2727
+ this.serverId = data._id?.server ?? serverId;
2728
+ this.joinedAt = new Date(data.joined_at);
2313
2729
  this.roles = new MemberRoleManager(this);
2314
2730
  this._patch(data);
2315
2731
  }
2316
2732
  _patch(data) {
2317
2733
  if (data.nickname !== void 0) this.nickname = data.nickname;
2318
- if (data.avatar !== void 0) this.avatar = data.avatar;
2734
+ if (data.avatar !== void 0) this.avatar = data.avatar ? new Attachment(this.client, data.avatar) : null;
2319
2735
  if (data.roles !== void 0) this._roles = data.roles;
2320
2736
  if (data.timeout !== void 0) this.timeout = data.timeout ? new Date(data.timeout) : null;
2321
- if (data.can_publish !== void 0) this.canPublish = data.canPublish;
2322
- if (data.can_recieve !== void 0) this.canRecieve = data.canRecieve;
2737
+ if (data.can_publish !== void 0) this.canPublish = data.can_publish;
2738
+ if (data.can_receive !== void 0) this.canRecieve = data.can_receive;
2323
2739
  }
2324
2740
  /**
2325
2741
  * Get member role IDs
@@ -2338,15 +2754,15 @@ var Member = class extends Base {
2338
2754
  /** Calculates the member's total permissions using BigInt */
2339
2755
  get permissions() {
2340
2756
  const server = this.server;
2341
- if (!server) return 0n;
2757
+ if (!server) return new Permissions(0n);
2758
+ if (server.ownerId === this.id) {
2759
+ return new Permissions(PermissionFlags.GrantAllSafe);
2760
+ }
2342
2761
  let totalPerms = server.defaultPermissions ?? 0n;
2343
2762
  for (const role of this.roles.cache.values()) {
2344
- totalPerms |= BigInt(role.permissions);
2345
- }
2346
- if (server.ownerId === this.id) {
2347
- return PermissionFlags.GrantAllSafe;
2763
+ totalPerms |= BigInt(role.permissions.bitfield);
2348
2764
  }
2349
- return totalPerms;
2765
+ return new Permissions(totalPerms);
2350
2766
  }
2351
2767
  /** Get avatar URL for this member, or null if they don't have one.
2352
2768
  * @example
@@ -2410,10 +2826,6 @@ var Member = class extends Base {
2410
2826
  async setNickname(nickname) {
2411
2827
  return this.edit({ nickname });
2412
2828
  }
2413
- /** Checks if the member has a specific permission */
2414
- hasPermission(permission) {
2415
- return Permissions.has(this.permissions, permission);
2416
- }
2417
2829
  /**
2418
2830
  * Edit this member.
2419
2831
  * @param options The options to edit the member with (nickname, roles, timeout, etc.)
@@ -2468,17 +2880,14 @@ var MemberManager = class extends BaseManager {
2468
2880
  * @internal
2469
2881
  */
2470
2882
  extractId(data) {
2471
- return data.user_id ?? data.id ?? (typeof data._id === "string" ? data._id : data._id?.user);
2883
+ return data._id?.user;
2472
2884
  }
2473
2885
  /**
2474
2886
  * Tell BaseManager how to build a Member
2475
2887
  * @internal
2476
2888
  */
2477
2889
  construct(data) {
2478
- if (!data.server_id && !data.serverId) {
2479
- data.serverId = this.server.id;
2480
- }
2481
- return new Member(this.client, data);
2890
+ return new Member(this.client, data, this.server.id);
2482
2891
  }
2483
2892
  /**
2484
2893
  * Resolve a string or mention to Member
@@ -2537,23 +2946,22 @@ var MemberManager = class extends BaseManager {
2537
2946
  * const onlineMembers = await server.members.fetchMany({ exclude_offline: true });
2538
2947
  */
2539
2948
  async fetchMany(options = {}) {
2540
- const params = new URLSearchParams();
2541
- if (options.exclude_offline !== void 0) {
2542
- params.append("exclude_offline", options.exclude_offline.toString());
2949
+ const query = {};
2950
+ if (options.excludeOffline !== void 0) {
2951
+ query.exclude_offline = options.excludeOffline;
2543
2952
  }
2544
- const queryString = params.toString();
2545
- const endpoint = `/servers/${this.server.id}/members${queryString ? `?${queryString}` : ""}`;
2546
- const data = await this.client.rest.get(endpoint);
2547
- if (data.users && Array.isArray(data.users)) {
2953
+ const data = await this.client.rest.get(`/servers/${this.server.id}/members`, query);
2954
+ if (data.users) {
2548
2955
  for (const userData of data.users) {
2549
2956
  this.client.users._add(userData);
2550
2957
  }
2551
2958
  }
2552
2959
  const fetched = new Collection();
2553
- const rawMembers = data.members || (Array.isArray(data) ? data : []);
2554
- for (const rawMember of rawMembers) {
2555
- const member = this._add(rawMember);
2556
- fetched.set(member.id, member);
2960
+ if (data.members) {
2961
+ for (const rawMember of data.members) {
2962
+ const member = this._add(rawMember);
2963
+ fetched.set(member.id, member);
2964
+ }
2557
2965
  }
2558
2966
  return fetched;
2559
2967
  }
@@ -2656,11 +3064,17 @@ var ServerChannelManager = class {
2656
3064
  async create(options) {
2657
3065
  if (!options.name) throw new Error("A channel name must be provided.");
2658
3066
  const payload = {
2659
- name: options.name,
2660
- type: options.type ?? "Text",
2661
- description: options.description,
2662
- nsfw: options.nsfw ?? false
3067
+ name: options.name
2663
3068
  };
3069
+ if (options.nsfw !== void 0) {
3070
+ payload.nsfw = options.nsfw;
3071
+ }
3072
+ if (options.type !== void 0) {
3073
+ payload.type = options.type;
3074
+ }
3075
+ if (options.description !== void 0) {
3076
+ payload.description = options.description;
3077
+ }
2664
3078
  if (options.type === "Voice" && options.voice?.max_users) {
2665
3079
  payload.voice = { max_users: options.voice.max_users };
2666
3080
  }
@@ -2680,7 +3094,8 @@ var Role = class extends Base {
2680
3094
  color = null;
2681
3095
  hoist = false;
2682
3096
  rank = 0;
2683
- permissions = 0n;
3097
+ icon = null;
3098
+ _permissions = 0n;
2684
3099
  constructor(client, data, serverId) {
2685
3100
  super(client, data);
2686
3101
  this.serverId = serverId;
@@ -2692,19 +3107,20 @@ var Role = class extends Base {
2692
3107
  */
2693
3108
  _patch(data) {
2694
3109
  if (data.name !== void 0) this.name = data.name;
2695
- if (data.color !== void 0) this.color = data.color;
3110
+ if (data.colour !== void 0) this.color = data.colour;
2696
3111
  if (data.hoist !== void 0) this.hoist = data.hoist;
2697
3112
  if (data.rank !== void 0) this.rank = data.rank;
3113
+ if (data.icon !== void 0) this.icon = data.icon !== null ? new Attachment(this.client, data.icon) : null;
2698
3114
  if (data.permissions !== void 0) {
2699
3115
  try {
2700
3116
  if (typeof data.permissions === "object" && data.permissions !== null) {
2701
- const allowPerms = data.permissions.a ?? data.permissions[0] ?? 0;
2702
- this.permissions = BigInt(allowPerms);
3117
+ const allowPerms = data.permissions.a ?? 0;
3118
+ this._permissions = BigInt(allowPerms);
2703
3119
  } else {
2704
- this.permissions = BigInt(data.permissions);
3120
+ this._permissions = BigInt(data.permissions);
2705
3121
  }
2706
3122
  } catch {
2707
- this.permissions = 0n;
3123
+ this._permissions = 0n;
2708
3124
  }
2709
3125
  }
2710
3126
  }
@@ -2716,12 +3132,10 @@ var Role = class extends Base {
2716
3132
  return this.client.servers.cache.get(this.serverId);
2717
3133
  }
2718
3134
  /**
2719
- * Checks whether this role has a specific permission.
2720
- * @param permission The permission to check for.
2721
- * @returns True if the role has the permission.
3135
+ * Permissions for this role
2722
3136
  */
2723
- hasPermission(permission) {
2724
- return Permissions.has(this.permissions, permission);
3137
+ get permissions() {
3138
+ return new Permissions(this._permissions);
2725
3139
  }
2726
3140
  /**
2727
3141
  * Fetches this role directly from the API to ensure data is up to date.
@@ -2749,10 +3163,10 @@ var Role = class extends Base {
2749
3163
  * @throws {Error} If the API request fails (e.g., lack of permissions).
2750
3164
  * @example
2751
3165
  * // Change the role's name and color
2752
- * await role.edit({ name: "Senior Admin", colour: "#FFD700" });
3166
+ * await role.edit({ name: "Senior Admin", color: "#FFD700" });
2753
3167
  *
2754
3168
  * // Remove the custom color from the role
2755
- * await role.edit({ colour: null });
3169
+ * await role.edit({ color: null });
2756
3170
  */
2757
3171
  async edit(options) {
2758
3172
  let server = this.server;
@@ -2811,6 +3225,73 @@ var Role = class extends Base {
2811
3225
  await server.roles.setRanks(filteredRoles);
2812
3226
  return this;
2813
3227
  }
3228
+ /**
3229
+ * Change the name for this role
3230
+ * @param name The new name for the role
3231
+ * @returns A promise that resolves to this updated Role object.
3232
+ * @throws {Error} If API request fails.
3233
+ * @example
3234
+ * // Change the role's name
3235
+ * await role.setName("New Role Name");
3236
+ * console.log(`Role's new name: ${role.name}`);
3237
+ */
3238
+ async setName(name) {
3239
+ return await this.edit({ name });
3240
+ }
3241
+ /**
3242
+ * Change the color for this role, it can be a HEX or CSS colours
3243
+ * @param {[string]} color The new color for the role
3244
+ * @returns A promise that resolves to this updated Role object.
3245
+ * @throws {Error} If API request fails
3246
+ * @example
3247
+ * // Change the role's color
3248
+ * await role.setColour("#FF0000");
3249
+ * console.log(`Role's new color: ${role.color}`);
3250
+ *
3251
+ * // Use CSS color linear-graident
3252
+ * await role.setColour("linear-gradient(90deg, #FF0000, #0000FF)");
3253
+ * console.log(`Role's new color: ${role.color}`);
3254
+ *
3255
+ * // Remove the custom color from the role
3256
+ * await role.setColour(null);
3257
+ * console.log(`Role's color removed, current color: ${role.color}`);
3258
+ */
3259
+ async setColor(color) {
3260
+ return await this.edit({ color });
3261
+ }
3262
+ /**
3263
+ * Edit the icon of this role
3264
+ * @param icon Autumn ID for the new icon, or null to remove the custom icon
3265
+ * @returns A promise that resolves to this updated Role object.
3266
+ * @throws {Error} If API request fails
3267
+ * @example
3268
+ * // Set a new icon for the role
3269
+ * await role.setIcon("AUTUMN_ID_FOR_ICON");
3270
+ * console.log(`Role's new icon: ${role.icon}`);
3271
+ *
3272
+ * // Use AttachmentBuilder to upload a new icon file
3273
+ * import { readFile } from "node:fs/promises";
3274
+ * const iconFile = await readFile("./a.jpg");
3275
+ * const attachment = new AttachmentBuilder(iconFile, "a.jpg");
3276
+ * await role.setIcon(attachment);
3277
+ * console.log(`Role's new icon: ${role.icon}`);
3278
+ */
3279
+ async setIcon(icon) {
3280
+ return await this.edit({ icon });
3281
+ }
3282
+ /**
3283
+ * Change the hoist status for this role
3284
+ * @param hoist The new hoist status for the role
3285
+ * @returns A promise that resolves to this updated Role object.
3286
+ * @throws {Error} If API request fails
3287
+ * @example
3288
+ * // Enable hoisting for the role
3289
+ * await role.setHoist(true);
3290
+ * console.log(`Role is now hoisted: ${role.hoist}`);
3291
+ */
3292
+ async setHoist(hoist) {
3293
+ return await this.edit({ hoist });
3294
+ }
2814
3295
  /**
2815
3296
  * Customizer for Node.js `console.log` and `util.inspect`.
2816
3297
  * Hides the cyclic client reference and raw serverId for a cleaner output.
@@ -2836,7 +3317,7 @@ var RoleManager = class extends BaseManager {
2836
3317
  * Tell BaseManager how to find the ID for Roles
2837
3318
  */
2838
3319
  extractId(data) {
2839
- return data._id ?? data.id;
3320
+ return data._id;
2840
3321
  }
2841
3322
  /**
2842
3323
  * Tell BaseManager how to build a Role
@@ -2852,7 +3333,7 @@ var RoleManager = class extends BaseManager {
2852
3333
  * @returns The newly created or updated Role object.
2853
3334
  */
2854
3335
  _add(data, idParam) {
2855
- const id = idParam ?? data._id ?? data.id;
3336
+ const id = idParam ?? data._id;
2856
3337
  const existing = this.cache.get(id);
2857
3338
  if (existing) {
2858
3339
  existing._patch(data);
@@ -2915,7 +3396,7 @@ var RoleManager = class extends BaseManager {
2915
3396
  name: options.name
2916
3397
  };
2917
3398
  const data = await this.client.rest.post(`/servers/${this.server.id}/roles`, payload);
2918
- return this._add(data);
3399
+ return this._add(data.role);
2919
3400
  }
2920
3401
  /**
2921
3402
  * Fetches a Role from the API or resolves it from the local cache.
@@ -2948,7 +3429,7 @@ var RoleManager = class extends BaseManager {
2948
3429
  }
2949
3430
  /**
2950
3431
  * Edits an existing role in the server.
2951
- * @param role The RoleResolvable to edit.
3432
+ * @param role The {@link RoleResolvable} to edit.
2952
3433
  * @param options The fields to update.
2953
3434
  * @returns A promise that resolves to the updated Role.
2954
3435
  * @throws {TypeError} If invalid options or RoleResolvable are provided.
@@ -2969,11 +3450,21 @@ var RoleManager = class extends BaseManager {
2969
3450
  const remove = [];
2970
3451
  if (options.name !== void 0) payload.name = options.name;
2971
3452
  if (options.hoist !== void 0) payload.hoist = options.hoist;
2972
- if (options.colour !== void 0) {
2973
- if (options.colour === null) {
3453
+ if (options.color !== void 0) {
3454
+ if (options.color === null) {
2974
3455
  remove.push("Colour");
2975
3456
  } else {
2976
- payload.colour = options.colour;
3457
+ payload.colour = options.color;
3458
+ }
3459
+ }
3460
+ if (options.icon !== void 0) {
3461
+ if (options.icon === null) {
3462
+ remove.push("Icon");
3463
+ } else {
3464
+ const resolvedIcon = await resolveAttachment(this.client.rest, options.icon, "icons");
3465
+ if (resolvedIcon !== void 0) {
3466
+ payload.icon = resolvedIcon;
3467
+ }
2977
3468
  }
2978
3469
  }
2979
3470
  if (remove.length > 0) {
@@ -2982,7 +3473,8 @@ var RoleManager = class extends BaseManager {
2982
3473
  if (Object.keys(payload).length === 0) {
2983
3474
  return this.fetch(id);
2984
3475
  }
2985
- const data = await this.client.rest.patch(`/servers/${this.server.id}/roles/${id}`, payload);
3476
+ const endpoint = `/servers/${this.server.id}/roles/${id}`;
3477
+ const data = await this.client.rest.patch(endpoint, payload);
2986
3478
  return this._add(data, id);
2987
3479
  }
2988
3480
  /**
@@ -3058,7 +3550,7 @@ var RoleManager = class extends BaseManager {
3058
3550
  const payload = {
3059
3551
  ranks: mappedIds
3060
3552
  };
3061
- const data = await this.client.rest.put(`/servers/${this.server.id}/roles`, payload);
3553
+ const data = await this.client.rest.patch(`/servers/${this.server.id}/roles/ranks`, payload);
3062
3554
  this.server._patch(data);
3063
3555
  return this.server;
3064
3556
  }
@@ -3070,7 +3562,7 @@ var ServerInvite = class {
3070
3562
  creatorId;
3071
3563
  channelId;
3072
3564
  constructor(data) {
3073
- this.code = data._id ?? data.code;
3565
+ this.code = data._id;
3074
3566
  this.creatorId = data.creator;
3075
3567
  this.channelId = data.channel;
3076
3568
  }
@@ -3087,7 +3579,7 @@ var ServerInviteManager = class extends BaseManager {
3087
3579
  this.server = server;
3088
3580
  }
3089
3581
  extractId(data) {
3090
- return data._id ?? data.code;
3582
+ return data._id;
3091
3583
  }
3092
3584
  construct(data) {
3093
3585
  return new ServerInvite(data);
@@ -3097,9 +3589,8 @@ var ServerInviteManager = class extends BaseManager {
3097
3589
  */
3098
3590
  async fetch() {
3099
3591
  const data = await this.client.rest.get(`/servers/${this.server.id}/invites`);
3100
- const rawInvites = Array.isArray(data) ? data : [];
3101
3592
  const fetched = new Collection();
3102
- for (const raw of rawInvites) {
3593
+ for (const raw of data) {
3103
3594
  const invite = this._add(raw);
3104
3595
  fetched.set(invite.code, invite);
3105
3596
  }
@@ -3112,7 +3603,7 @@ var ServerBan = class {
3112
3603
  userId;
3113
3604
  reason;
3114
3605
  constructor(data) {
3115
- this.userId = data._id?.user ?? data.id;
3606
+ this.userId = data._id?.user;
3116
3607
  this.reason = data.reason ?? null;
3117
3608
  }
3118
3609
  _patch(data) {
@@ -3219,7 +3710,7 @@ var Server = class extends Base {
3219
3710
  ownerId;
3220
3711
  analytics = false;
3221
3712
  banner = null;
3222
- categories = [];
3713
+ categories = null;
3223
3714
  description = null;
3224
3715
  discoverable = false;
3225
3716
  flags = 0;
@@ -3272,13 +3763,6 @@ var Server = class extends Base {
3272
3763
  this.roles._add({ id, ...roleData });
3273
3764
  }
3274
3765
  }
3275
- if (data.emojis !== void 0) {
3276
- if (Array.isArray(data.emojis)) {
3277
- for (const emoji of data.emojis) {
3278
- this.emojis._add(emoji);
3279
- }
3280
- }
3281
- }
3282
3766
  if (clear && Array.isArray(clear)) {
3283
3767
  for (const field of clear) {
3284
3768
  switch (field) {
@@ -3326,7 +3810,7 @@ var ServerManager = class extends BaseManager {
3326
3810
  * Tell BaseManager how to find the ID for Servers
3327
3811
  */
3328
3812
  extractId(data) {
3329
- return data._id ?? data.id;
3813
+ return data._id;
3330
3814
  }
3331
3815
  /**
3332
3816
  * Tell BaseManager how to build a Server
@@ -3367,21 +3851,19 @@ var ServerManager = class extends BaseManager {
3367
3851
  payload.system_messages = {};
3368
3852
  const sm = options.systemMessages;
3369
3853
  if (sm.userJoined !== void 0) {
3370
- if (sm.userJoined === null) remove.push("SystemMessageUserJoined");
3371
- else payload.system_messages.user_joined = sm.userJoined;
3854
+ payload.system_messages.user_joined = sm.userJoined;
3372
3855
  }
3373
3856
  if (sm.userLeft !== void 0) {
3374
- if (sm.userLeft === null) remove.push("SystemMessageUserLeft");
3375
- else payload.system_messages.user_left = sm.userLeft;
3857
+ payload.system_messages.user_left = sm.userLeft;
3376
3858
  }
3377
3859
  if (sm.userKicked !== void 0) {
3378
- if (sm.userKicked === null) remove.push("SystemMessageUserKicked");
3379
- else payload.system_messages.user_kicked = sm.userKicked;
3860
+ payload.system_messages.user_kicked = sm.userKicked;
3380
3861
  }
3381
3862
  if (sm.userBanned !== void 0) {
3382
- if (sm.userBanned === null) remove.push("SystemMessageUserBanned");
3383
- else payload.system_messages.user_banned = sm.userBanned;
3863
+ payload.system_messages.user_banned = sm.userBanned;
3384
3864
  }
3865
+ } else if (options.systemMessages === null) {
3866
+ remove.push("SystemMessages");
3385
3867
  }
3386
3868
  if (options.categories !== void 0) payload.categories = options.categories;
3387
3869
  if (options.analytics !== void 0) payload.analytics = options.analytics;
@@ -3404,7 +3886,7 @@ var UserManager = class extends BaseManager {
3404
3886
  * Tell BaseManager how to find the ID for Users
3405
3887
  */
3406
3888
  extractId(data) {
3407
- return data._id ?? data.id;
3889
+ return data._id;
3408
3890
  }
3409
3891
  /**
3410
3892
  * Tell BaseManager how to build a User
@@ -3539,7 +4021,7 @@ var UserManager = class extends BaseManager {
3539
4021
  if (Object.keys(payload).length === 0) {
3540
4022
  return this.fetch("@me");
3541
4023
  }
3542
- const data = await this.client.rest.patch(`/users/@me`, payload);
4024
+ const data = await this.client.rest.patch(`/users/${this.client.user?.id}`, payload);
3543
4025
  return this._add(data);
3544
4026
  }
3545
4027
  /**
@@ -3699,12 +4181,17 @@ var EmbedBuilder = class {
3699
4181
  return { ...this.data };
3700
4182
  }
3701
4183
  };
4184
+
4185
+ // src/index.ts
4186
+ import * as API from "stoat-api";
3702
4187
  export {
4188
+ API,
3703
4189
  Attachment,
4190
+ AttachmentBuilder,
3704
4191
  Base,
3705
4192
  BaseChannel,
4193
+ BitField,
3706
4194
  ChannelManager,
3707
- ChannelType,
3708
4195
  Client,
3709
4196
  ClientUser,
3710
4197
  Collection,
@@ -3734,8 +4221,6 @@ export {
3734
4221
  TextChannel,
3735
4222
  UnknownChannel,
3736
4223
  User,
3737
- UserManager,
3738
- UserPresence,
3739
- UserRelationship
4224
+ UserManager
3740
4225
  };
3741
4226
  //# sourceMappingURL=index.js.map