@stoatx/client 0.7.0 → 0.9.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.cjs CHANGED
@@ -33,6 +33,8 @@ __export(index_exports, {
33
33
  API: () => API,
34
34
  Attachment: () => Attachment,
35
35
  AttachmentBuilder: () => AttachmentBuilder,
36
+ AudioPlayer: () => AudioPlayer,
37
+ AudioResource: () => AudioResource,
36
38
  Base: () => Base,
37
39
  BaseChannel: () => BaseChannel,
38
40
  BitField: () => BitField,
@@ -67,7 +69,10 @@ __export(index_exports, {
67
69
  TextChannel: () => TextChannel,
68
70
  UnknownChannel: () => UnknownChannel,
69
71
  User: () => User,
70
- UserManager: () => UserManager
72
+ UserManager: () => UserManager,
73
+ VoiceConnection: () => VoiceConnection,
74
+ VoiceManager: () => VoiceManager,
75
+ decodeTime: () => import_ulid8.decodeTime
71
76
  });
72
77
  module.exports = __toCommonJS(index_exports);
73
78
 
@@ -522,7 +527,7 @@ var MessageMentions = class _MessageMentions {
522
527
  static parseChannelIds(content) {
523
528
  return [...content.matchAll(/<#([A-Z0-9]+)>/g)].flatMap((m) => m[1] ? [m[1]] : []);
524
529
  }
525
- [import_node_util.default.inspect.custom](depth, options, inspect12) {
530
+ [import_node_util.default.inspect.custom](depth, options, inspect13) {
526
531
  const { client, message, ...props } = this;
527
532
  const data = {
528
533
  ...props,
@@ -531,7 +536,7 @@ var MessageMentions = class _MessageMentions {
531
536
  users: this.users,
532
537
  roles: this.roles
533
538
  };
534
- return `${this.constructor.name} ${inspect12(data, { ...options, depth: depth ?? options.depth })}`;
539
+ return `${this.constructor.name} ${inspect13(data, { ...options, depth: depth ?? options.depth })}`;
535
540
  }
536
541
  };
537
542
 
@@ -543,7 +548,8 @@ var Message = class extends Base {
543
548
  embeds = [];
544
549
  attachments = [];
545
550
  editedAt = null;
546
- createdAt = null;
551
+ createdAt;
552
+ createdTimestamp;
547
553
  flags = 0;
548
554
  interactions = null;
549
555
  masquerade = null;
@@ -555,10 +561,9 @@ var Message = class extends Base {
555
561
  super(client, data);
556
562
  this.authorId = data.author;
557
563
  this.channelId = data.channel;
558
- const timestamp = (0, import_ulid.decodeTime)(this.id);
559
- if (timestamp) {
560
- this.createdAt = new Date(timestamp);
561
- }
564
+ const timestamp = (0, import_ulid.decodeTime)(data._id);
565
+ this.createdAt = new Date(timestamp);
566
+ this.createdTimestamp = timestamp;
562
567
  if (data.attachments) {
563
568
  this.attachments = data.attachments.map((fileData) => new Attachment(this.client, fileData));
564
569
  }
@@ -739,7 +744,7 @@ var Message = class extends Base {
739
744
  }
740
745
  }
741
746
  // This tells Node.js exactly how to print this object in console.log()
742
- [util3.inspect.custom](depth, options, inspect12) {
747
+ [util3.inspect.custom](depth, options, inspect13) {
743
748
  const { client, authorId, channelId, ...props } = this;
744
749
  const data = {
745
750
  ...props,
@@ -748,11 +753,12 @@ var Message = class extends Base {
748
753
  server: this.server,
749
754
  member: this.member
750
755
  };
751
- return `${this.constructor.name} ${inspect12(data, { ...options, depth: depth ?? options.depth })}`;
756
+ return `${this.constructor.name} ${inspect13(data, { ...options, depth: depth ?? options.depth })}`;
752
757
  }
753
758
  };
754
759
 
755
760
  // src/structures/User.ts
761
+ var import_ulid2 = require("ulid");
756
762
  var User = class extends Base {
757
763
  discriminator;
758
764
  online;
@@ -765,11 +771,17 @@ var User = class extends Base {
765
771
  flags;
766
772
  privileged;
767
773
  status;
774
+ createdAt;
775
+ createdTimestamp;
776
+ pronouns = null;
768
777
  constructor(client, data) {
769
778
  super(client, data);
770
779
  this.bot = false;
771
780
  this.privileged = false;
772
781
  this.flags = 0;
782
+ const timestamp = (0, import_ulid2.decodeTime)(data._id);
783
+ this.createdAt = new Date(timestamp);
784
+ this.createdTimestamp = timestamp;
773
785
  this._patch(data);
774
786
  }
775
787
  _patch(data, clear) {
@@ -777,6 +789,7 @@ var User = class extends Base {
777
789
  if (data.discriminator !== void 0) this.discriminator = data.discriminator;
778
790
  if (data.online !== void 0) this.online = data.online;
779
791
  if (data.relationship !== void 0) this.relationship = data.relationship;
792
+ if (data.pronouns !== void 0) this.pronouns = data.pronouns;
780
793
  if (data.display_name !== void 0) this.displayName = data.display_name;
781
794
  if (data.badges !== void 0) this.badges = data.badges;
782
795
  if (data.flags !== void 0) this.flags = data.flags;
@@ -790,9 +803,23 @@ var User = class extends Base {
790
803
  }
791
804
  if (clear && Array.isArray(clear)) {
792
805
  for (const field of clear) {
793
- if (field === "Avatar") this.avatar = null;
794
- if (field === "StatusText" && this.status) this.status.text = null;
795
- if (field === "DisplayName") this.displayName = null;
806
+ switch (field) {
807
+ case "Avatar":
808
+ this.avatar = null;
809
+ break;
810
+ case "DisplayName":
811
+ this.displayName = null;
812
+ break;
813
+ case "Pronouns":
814
+ this.pronouns = null;
815
+ break;
816
+ case "StatusText":
817
+ this.status.text = null;
818
+ break;
819
+ case "StatusPresence":
820
+ this.status.presence = null;
821
+ break;
822
+ }
796
823
  }
797
824
  }
798
825
  }
@@ -908,11 +935,10 @@ var GatewayManager = class {
908
935
  }
909
936
  if (payload.emojis) {
910
937
  for (const rawEmoji of payload.emojis) {
911
- const emoji = this.client.emojis._add(rawEmoji);
912
938
  if (rawEmoji.parent && rawEmoji.parent.type === "Server") {
913
939
  const server = this.client.servers.cache.get(rawEmoji.parent.id);
914
940
  if (server) {
915
- server.emojis._add(emoji);
941
+ server.emojis._add(rawEmoji);
916
942
  }
917
943
  }
918
944
  }
@@ -1090,7 +1116,7 @@ var GatewayManager = class {
1090
1116
  case "ServerMemberJoin": {
1091
1117
  const server = this.client.servers.cache.get(payload.id);
1092
1118
  if (server) {
1093
- const member = server.members._add({ user: payload.user });
1119
+ const member = server.members._add(payload.member);
1094
1120
  this.client.emit("serverMemberJoin", member);
1095
1121
  }
1096
1122
  break;
@@ -1108,7 +1134,7 @@ var GatewayManager = class {
1108
1134
  if (payload.reason === "Ban") {
1109
1135
  if (server) {
1110
1136
  const dummyBanPayload = {
1111
- id: payload.user,
1137
+ _id: payload.user,
1112
1138
  reason: null
1113
1139
  };
1114
1140
  server.bans._add(dummyBanPayload);
@@ -1122,11 +1148,10 @@ var GatewayManager = class {
1122
1148
  break;
1123
1149
  }
1124
1150
  case "EmojiCreate": {
1125
- const emoji = this.client.emojis._add(payload);
1126
1151
  if (payload.parent?.type === "Server") {
1127
1152
  const server = this.client.servers.cache.get(payload.parent.id);
1128
1153
  if (server) {
1129
- server.emojis._add(emoji);
1154
+ server.emojis._add(payload);
1130
1155
  }
1131
1156
  }
1132
1157
  break;
@@ -1428,13 +1453,14 @@ var RESTManager = class {
1428
1453
  this.client.emit("debug", `Bucket [${method}:${endpoint}] exhausted. Waiting ${waitTime}ms proactively...`);
1429
1454
  await sleep(waitTime);
1430
1455
  }
1456
+ const isBodyMethod = ["post", "patch", "put"].includes(method.toLowerCase());
1431
1457
  const response = await fetch(url, {
1432
1458
  method: method.toUpperCase(),
1433
1459
  headers: {
1434
1460
  "X-Bot-Token": this.token,
1435
1461
  "Content-Type": "application/json"
1436
1462
  },
1437
- ...body !== void 0 ? { body: JSON.stringify(body) } : {}
1463
+ ...isBodyMethod ? { body: JSON.stringify(body ?? {}) } : {}
1438
1464
  });
1439
1465
  const remainingHeader = response.headers.get("x-ratelimit-remaining");
1440
1466
  const resetAfterHeader = response.headers.get("x-ratelimit-reset-after");
@@ -1525,7 +1551,7 @@ var BaseManager = class {
1525
1551
  _add(data) {
1526
1552
  const id = this.extractId(data);
1527
1553
  const existing = this.cache.get(id);
1528
- if (existing && typeof existing._patch === "function") {
1554
+ if (existing && this.isPatchable(existing)) {
1529
1555
  existing._patch(data);
1530
1556
  return existing;
1531
1557
  }
@@ -1533,6 +1559,9 @@ var BaseManager = class {
1533
1559
  this.cache.set(id, structure);
1534
1560
  return structure;
1535
1561
  }
1562
+ isPatchable(value) {
1563
+ return typeof value._patch === "function";
1564
+ }
1536
1565
  };
1537
1566
 
1538
1567
  // src/builders/AttachmentBuilder.ts
@@ -1970,9 +1999,13 @@ var BaseChannel = class extends Base {
1970
1999
  isGroup() {
1971
2000
  return this.type === "Group";
1972
2001
  }
2002
+ isVoice() {
2003
+ return this.isText() && this.voice !== null;
2004
+ }
1973
2005
  };
1974
2006
 
1975
2007
  // src/structures/TextChannel.ts
2008
+ var import_ulid3 = require("ulid");
1976
2009
  var TextChannel = class extends BaseChannel {
1977
2010
  name;
1978
2011
  serverId;
@@ -1983,9 +2016,14 @@ var TextChannel = class extends BaseChannel {
1983
2016
  nsfw;
1984
2017
  slowmode;
1985
2018
  voice;
2019
+ createdAt;
2020
+ createdTimestamp;
1986
2021
  constructor(client, data) {
1987
2022
  super(client, data);
1988
2023
  this.serverId = data.server;
2024
+ const timestamp = (0, import_ulid3.decodeTime)(data._id);
2025
+ this.createdTimestamp = timestamp;
2026
+ this.createdAt = new Date(timestamp);
1989
2027
  this.defaultPermissions = data.default_permissions;
1990
2028
  this.description = data.description;
1991
2029
  if (data.icon !== void 0) {
@@ -2010,10 +2048,10 @@ var TextChannel = class extends BaseChannel {
2010
2048
  this.icon = null;
2011
2049
  break;
2012
2050
  case "DefaultPermissions":
2013
- this.defaultPermissions = data.default_permissions;
2051
+ this.defaultPermissions = null;
2014
2052
  break;
2015
2053
  case "Voice":
2016
- this.voice = data.voice;
2054
+ this.voice = null;
2017
2055
  break;
2018
2056
  }
2019
2057
  }
@@ -2208,6 +2246,7 @@ var DMChannel = class extends BaseChannel {
2208
2246
 
2209
2247
  // src/structures/GroupChannel.ts
2210
2248
  var util5 = __toESM(require("util"), 1);
2249
+ var import_ulid4 = require("ulid");
2211
2250
  var GroupChannel = class extends BaseChannel {
2212
2251
  name;
2213
2252
  ownerId;
@@ -2216,8 +2255,13 @@ var GroupChannel = class extends BaseChannel {
2216
2255
  icon = null;
2217
2256
  lastMessageId = null;
2218
2257
  nsfw = false;
2258
+ createdAt;
2259
+ createdTimestamp;
2219
2260
  constructor(client, data) {
2220
2261
  super(client, data);
2262
+ const timestamp = (0, import_ulid4.decodeTime)(data._id);
2263
+ this.createdAt = new Date(timestamp);
2264
+ this.createdTimestamp = timestamp;
2221
2265
  this._patch(data);
2222
2266
  }
2223
2267
  _patch(data, clear) {
@@ -2233,9 +2277,6 @@ var GroupChannel = class extends BaseChannel {
2233
2277
  if (clear && Array.isArray(clear)) {
2234
2278
  for (const field of clear) {
2235
2279
  switch (field) {
2236
- case "Name":
2237
- this.name = "";
2238
- break;
2239
2280
  case "Description":
2240
2281
  this.description = null;
2241
2282
  break;
@@ -2267,9 +2308,9 @@ var GroupChannel = class extends BaseChannel {
2267
2308
  async setDefaultPermissions(permissions) {
2268
2309
  return await this.client.channels.setDefaultPermissions(this.id, permissions);
2269
2310
  }
2270
- [util5.inspect.custom](_depth, options, inspect12) {
2311
+ [util5.inspect.custom](_depth, options, inspect13) {
2271
2312
  const { client, ...props } = this;
2272
- return `${this.constructor.name} ${inspect12(
2313
+ return `${this.constructor.name} ${inspect13(
2273
2314
  {
2274
2315
  ...props,
2275
2316
  owner: this.owner,
@@ -2280,10 +2321,21 @@ var GroupChannel = class extends BaseChannel {
2280
2321
  }
2281
2322
  };
2282
2323
 
2324
+ // src/structures/VoiceChannel.ts
2325
+ var VoiceChannel = class extends TextChannel {
2326
+ async join() {
2327
+ return this.client.voice.join(this.id, this.serverId);
2328
+ }
2329
+ async leave() {
2330
+ return this.client.voice.leave(this.id);
2331
+ }
2332
+ };
2333
+
2283
2334
  // src/utils/ChannelFactory.ts
2284
2335
  function createChannel(client, data) {
2285
2336
  switch (data.channel_type) {
2286
2337
  case "TextChannel":
2338
+ if (data.voice) return new VoiceChannel(client, data);
2287
2339
  return new TextChannel(client, data);
2288
2340
  case "DirectMessage":
2289
2341
  return new DMChannel(client, data);
@@ -2905,6 +2957,8 @@ var Member = class extends Base {
2905
2957
  _roles = [];
2906
2958
  // The date the member joined the server
2907
2959
  joinedAt;
2960
+ // The timestamp the member joined the server
2961
+ joinedTimestamp;
2908
2962
  // The date the member's timeout expires, or null if not timed out
2909
2963
  timeout = null;
2910
2964
  // Whatever the user can talk in Voice Chat
@@ -2913,20 +2967,53 @@ var Member = class extends Base {
2913
2967
  canRecieve = false;
2914
2968
  // Member roles manager
2915
2969
  roles;
2970
+ // Member pronouns
2971
+ pronouns = null;
2916
2972
  constructor(client, data, serverId) {
2917
2973
  super(client, { _id: data._id?.user });
2918
2974
  this.serverId = data._id?.server ?? serverId;
2919
- this.joinedAt = new Date(data.joined_at);
2975
+ const timestamp = new Date(data.joined_at);
2976
+ this.joinedAt = timestamp;
2977
+ this.joinedTimestamp = timestamp.getTime();
2920
2978
  this.roles = new MemberRoleManager(this);
2921
2979
  this._patch(data);
2922
2980
  }
2923
- _patch(data) {
2981
+ _patch(data, clear) {
2924
2982
  if (data.nickname !== void 0) this.nickname = data.nickname;
2925
2983
  if (data.avatar !== void 0) this.avatar = data.avatar ? new Attachment(this.client, data.avatar) : null;
2926
2984
  if (data.roles !== void 0) this._roles = data.roles;
2927
2985
  if (data.timeout !== void 0) this.timeout = data.timeout ? new Date(data.timeout) : null;
2928
2986
  if (data.can_publish !== void 0) this.canPublish = data.can_publish;
2929
2987
  if (data.can_receive !== void 0) this.canRecieve = data.can_receive;
2988
+ if (data.pronouns !== void 0) this.pronouns = data.pronouns;
2989
+ if (clear && Array.isArray(clear)) {
2990
+ for (const field of clear) {
2991
+ switch (field) {
2992
+ case "Avatar":
2993
+ this.avatar = null;
2994
+ break;
2995
+ case "Nickname":
2996
+ this.nickname = null;
2997
+ break;
2998
+ case "Pronouns":
2999
+ this.pronouns = null;
3000
+ break;
3001
+ case "CanPublish":
3002
+ this.canPublish = false;
3003
+ break;
3004
+ case "Timeout":
3005
+ this.timeout = null;
3006
+ break;
3007
+ case "Roles":
3008
+ this._roles = [];
3009
+ this.roles = new MemberRoleManager(this);
3010
+ break;
3011
+ case "CanReceive":
3012
+ this.canRecieve = false;
3013
+ break;
3014
+ }
3015
+ }
3016
+ }
2930
3017
  }
2931
3018
  /**
2932
3019
  * Get member role IDs
@@ -3046,9 +3133,9 @@ var Member = class extends Base {
3046
3133
  await server.members.kick(this.id);
3047
3134
  }
3048
3135
  /** @internal */
3049
- [util6.inspect.custom](depth, options, inspect12) {
3136
+ [util6.inspect.custom](depth, options, inspect13) {
3050
3137
  const { client, serverId, ...props } = this;
3051
- return `${this.constructor.name} ${inspect12(
3138
+ return `${this.constructor.name} ${inspect13(
3052
3139
  {
3053
3140
  ...props,
3054
3141
  user: this.user,
@@ -3279,6 +3366,7 @@ var ServerChannelManager = class {
3279
3366
 
3280
3367
  // src/structures/Role.ts
3281
3368
  var util9 = __toESM(require("util"), 1);
3369
+ var import_ulid5 = require("ulid");
3282
3370
  var Role = class extends Base {
3283
3371
  serverId;
3284
3372
  name;
@@ -3287,16 +3375,21 @@ var Role = class extends Base {
3287
3375
  rank = 0;
3288
3376
  icon = null;
3289
3377
  _permissions = 0n;
3378
+ createdAt;
3379
+ createdTimestamp;
3290
3380
  constructor(client, data, serverId) {
3291
3381
  super(client, data);
3292
3382
  this.serverId = serverId;
3383
+ const timestamp = (0, import_ulid5.decodeTime)(data._id);
3384
+ this.createdAt = new Date(timestamp);
3385
+ this.createdTimestamp = timestamp;
3293
3386
  this._patch(data);
3294
3387
  }
3295
3388
  /**
3296
3389
  * Updates the role instance with new data without losing the object reference.
3297
3390
  * @internal
3298
3391
  */
3299
- _patch(data) {
3392
+ _patch(data, clear) {
3300
3393
  if (data.name !== void 0) this.name = data.name;
3301
3394
  if (data.colour !== void 0) this.color = data.colour;
3302
3395
  if (data.hoist !== void 0) this.hoist = data.hoist;
@@ -3314,6 +3407,18 @@ var Role = class extends Base {
3314
3407
  this._permissions = 0n;
3315
3408
  }
3316
3409
  }
3410
+ if (clear && Array.isArray(clear)) {
3411
+ for (const field of clear) {
3412
+ switch (field) {
3413
+ case "Colour":
3414
+ this.color = null;
3415
+ break;
3416
+ case "Icon":
3417
+ this.icon = null;
3418
+ break;
3419
+ }
3420
+ }
3421
+ }
3317
3422
  }
3318
3423
  /**
3319
3424
  * The server this role belongs to.
@@ -3809,7 +3914,7 @@ var ServerBanManager = class extends BaseManager {
3809
3914
  this.server = server;
3810
3915
  }
3811
3916
  extractId(data) {
3812
- return data._id?.user ?? data.id;
3917
+ return data._id?.user;
3813
3918
  }
3814
3919
  construct(data) {
3815
3920
  return new ServerBan(data);
@@ -3821,11 +3926,6 @@ var ServerBanManager = class extends BaseManager {
3821
3926
  */
3822
3927
  async fetch() {
3823
3928
  const data = await this.client.rest.get(`/servers/${this.server.id}/bans`);
3824
- if (data.users && Array.isArray(data.users)) {
3825
- for (const userData of data.users) {
3826
- this.client.users._add(userData);
3827
- }
3828
- }
3829
3929
  const rawBans = data.bans || (Array.isArray(data) ? data : []);
3830
3930
  const fetched = new Collection();
3831
3931
  for (const rawBan of rawBans) {
@@ -3846,14 +3946,20 @@ var ServerBanManager = class extends BaseManager {
3846
3946
  };
3847
3947
 
3848
3948
  // src/structures/Emoji.ts
3949
+ var import_ulid6 = require("ulid");
3849
3950
  var Emoji = class extends Base {
3850
3951
  creatorId;
3851
3952
  name;
3852
3953
  parent;
3954
+ createdAt;
3955
+ createdTimestamp;
3853
3956
  animated = false;
3854
3957
  nsfw = false;
3855
3958
  constructor(client, data) {
3856
3959
  super(client, data);
3960
+ const timestamp = (0, import_ulid6.decodeTime)(data._id);
3961
+ this.createdAt = new Date(timestamp);
3962
+ this.createdTimestamp = timestamp;
3857
3963
  this._patch(data);
3858
3964
  }
3859
3965
  _patch(data) {
@@ -4031,6 +4137,114 @@ var EmojiManager = class extends BaseManager {
4031
4137
  }
4032
4138
  };
4033
4139
 
4140
+ // src/structures/Server.ts
4141
+ var import_ulid7 = require("ulid");
4142
+
4143
+ // src/structures/AuditLogEntry.ts
4144
+ var util12 = __toESM(require("util"), 1);
4145
+ function resolveTargetId(data) {
4146
+ if (data.target) return data.target;
4147
+ const action = data.action;
4148
+ switch (action.type) {
4149
+ case "ChannelCreate":
4150
+ case "ChannelEdit":
4151
+ case "ChannelDelete":
4152
+ case "ChannelRolePermissionsEdit":
4153
+ return action.channel;
4154
+ case "RoleCreate":
4155
+ case "RoleEdit":
4156
+ case "RoleDelete":
4157
+ return action.role;
4158
+ case "InviteCreate":
4159
+ case "InviteDelete":
4160
+ return action.invite;
4161
+ case "WebhookCreate":
4162
+ case "WebhookDelete":
4163
+ return action.webhook;
4164
+ case "EmojiCreate":
4165
+ case "EmojiUpdate":
4166
+ case "EmojiDelete":
4167
+ return action.emoji;
4168
+ case "MessageDelete":
4169
+ return action.channel;
4170
+ case "MessagePin":
4171
+ case "MessageUnpin":
4172
+ return action.message;
4173
+ case "MessageBulkDelete":
4174
+ return action.channel;
4175
+ default:
4176
+ return null;
4177
+ }
4178
+ }
4179
+ var AuditLogEntry = class extends Base {
4180
+ serverId;
4181
+ userId;
4182
+ targetId;
4183
+ reason;
4184
+ action;
4185
+ constructor(client, data) {
4186
+ super(client, data);
4187
+ this.serverId = data.server;
4188
+ this.userId = data.user;
4189
+ this.targetId = resolveTargetId(data);
4190
+ this.reason = data.reason ?? null;
4191
+ this.action = data.action;
4192
+ }
4193
+ /** The action tag, e.g. "ChannelEdit" — narrow `entry.action` on this. */
4194
+ get type() {
4195
+ return this.action.type;
4196
+ }
4197
+ get server() {
4198
+ return this.client.servers.cache.get(this.serverId);
4199
+ }
4200
+ /** The user who performed this action, if cached. */
4201
+ get executor() {
4202
+ return this.client.users.cache.get(this.userId);
4203
+ }
4204
+ /**
4205
+ * Best-effort resolve of `targetId` into the actual entity, picked by
4206
+ * `action.type` since a bare id alone doesn't say whether it's a member,
4207
+ * a role, a channel, etc.
4208
+ */
4209
+ get target() {
4210
+ if (!this.targetId) return void 0;
4211
+ const server = this.server;
4212
+ switch (this.action.type) {
4213
+ case "MemberEdit":
4214
+ case "MemberKick":
4215
+ return server?.members.cache.get(this.targetId);
4216
+ case "BanCreate":
4217
+ case "BanDelete":
4218
+ return this.client.users.cache.get(this.targetId);
4219
+ case "ChannelCreate":
4220
+ case "ChannelEdit":
4221
+ case "ChannelDelete":
4222
+ case "ChannelRolePermissionsEdit":
4223
+ return server?.channels.cache.get(this.targetId);
4224
+ case "RoleCreate":
4225
+ case "RoleEdit":
4226
+ case "RoleDelete":
4227
+ return server?.roles.cache.get(this.targetId);
4228
+ default:
4229
+ return this.targetId;
4230
+ }
4231
+ }
4232
+ /**
4233
+ * Customizer for Node.js `console.log` and `util.inspect`.
4234
+ * Hides the cyclic client reference for a cleaner output.
4235
+ * @internal
4236
+ */
4237
+ [util12.inspect.custom]() {
4238
+ const { client, ...props } = this;
4239
+ return `${this.constructor.name} ${util12.inspect({
4240
+ ...props,
4241
+ type: this.type,
4242
+ executor: this.executor,
4243
+ target: this.target
4244
+ })}`;
4245
+ }
4246
+ };
4247
+
4034
4248
  // src/structures/Server.ts
4035
4249
  var Server = class extends Base {
4036
4250
  channelIds = [];
@@ -4051,6 +4265,8 @@ var Server = class extends Base {
4051
4265
  bans;
4052
4266
  invites;
4053
4267
  emojis;
4268
+ createdAt;
4269
+ createdTimestamp;
4054
4270
  constructor(client, data) {
4055
4271
  super(client, data);
4056
4272
  this.channels = new ServerChannelManager(client, this);
@@ -4059,6 +4275,9 @@ var Server = class extends Base {
4059
4275
  this.bans = new ServerBanManager(this.client, this);
4060
4276
  this.invites = new ServerInviteManager(this.client, this);
4061
4277
  this.emojis = new EmojiManager(this.client, this);
4278
+ const timestamp = (0, import_ulid7.decodeTime)(data._id);
4279
+ this.createdAt = new Date(timestamp);
4280
+ this.createdTimestamp = timestamp;
4062
4281
  this._patch(data);
4063
4282
  }
4064
4283
  /**
@@ -4101,6 +4320,12 @@ var Server = class extends Base {
4101
4320
  case "Icon":
4102
4321
  this.icon = null;
4103
4322
  break;
4323
+ case "Banner":
4324
+ this.banner = null;
4325
+ break;
4326
+ case "Categories":
4327
+ this.categories = null;
4328
+ break;
4104
4329
  }
4105
4330
  }
4106
4331
  }
@@ -4119,6 +4344,27 @@ var Server = class extends Base {
4119
4344
  async leave() {
4120
4345
  return this.client.rest.delete(`/servers/${this.id}/leave`);
4121
4346
  }
4347
+ /**
4348
+ * Fetch audit logs for this server
4349
+ * @param options Query params
4350
+ */
4351
+ async fetchAuditLogs(options) {
4352
+ const query = {};
4353
+ if (options?.user) query.user = options.user;
4354
+ if (options?.target) query.target = options.target;
4355
+ if (options?.type) query.type = options.type;
4356
+ if (options?.before) query.before = options.before;
4357
+ if (options?.after) query.after = options.after;
4358
+ if (options?.limit) query.limit = options.limit;
4359
+ const data = await this.client.rest.get(`/servers/${this.id}/audit_logs`, query);
4360
+ for (const user of data.users) this.client.users._add(user);
4361
+ for (const member of data.members) this.members._add(member);
4362
+ const entries = new Collection();
4363
+ for (const raw of data.audit_logs) {
4364
+ entries.set(raw._id, new AuditLogEntry(this.client, raw));
4365
+ }
4366
+ return entries;
4367
+ }
4122
4368
  /**
4123
4369
  * Fetches multiple members from this server.
4124
4370
  * @param options Filter options for the fetch request.
@@ -4130,7 +4376,7 @@ var Server = class extends Base {
4130
4376
  };
4131
4377
 
4132
4378
  // src/managers/ServerManager.ts
4133
- var util12 = __toESM(require("util"), 1);
4379
+ var util13 = __toESM(require("util"), 1);
4134
4380
  var ServerManager = class extends BaseManager {
4135
4381
  constructor(client, limit = Infinity) {
4136
4382
  super(client, limit);
@@ -4201,7 +4447,7 @@ var ServerManager = class extends BaseManager {
4201
4447
  const data = await this.client.rest.patch(`/servers/${serverId}`, payload);
4202
4448
  return this._add(data);
4203
4449
  }
4204
- [util12.inspect.custom]() {
4450
+ [util13.inspect.custom]() {
4205
4451
  return this.cache;
4206
4452
  }
4207
4453
  };
@@ -4429,6 +4675,237 @@ var SweeperManager = class {
4429
4675
  }
4430
4676
  };
4431
4677
 
4678
+ // src/voice/VoiceConnection.ts
4679
+ var import_rtc_node = require("@livekit/rtc-node");
4680
+ var import_node_events = require("events");
4681
+ var SAMPLE_RATE = 48e3;
4682
+ var CHANNELS = 2;
4683
+ var SAMPLES_PER_FRAME = 960;
4684
+ var BYTES_PER_FRAME = SAMPLES_PER_FRAME * CHANNELS * 2;
4685
+ var VoiceConnection = class extends import_node_events.EventEmitter {
4686
+ channelId;
4687
+ guildId;
4688
+ room;
4689
+ _status = "connecting";
4690
+ _player = null;
4691
+ _audioSource = null;
4692
+ _audioTrack = null;
4693
+ constructor(channelId, guildId) {
4694
+ super();
4695
+ this.channelId = channelId;
4696
+ this.guildId = guildId;
4697
+ this.room = new import_rtc_node.Room();
4698
+ this.room.on(import_rtc_node.RoomEvent.Disconnected, () => {
4699
+ this._status = "disconnected";
4700
+ this._player?.removeSubscriber(this);
4701
+ this.emit("disconnect");
4702
+ });
4703
+ }
4704
+ get status() {
4705
+ return this._status;
4706
+ }
4707
+ get player() {
4708
+ return this._player;
4709
+ }
4710
+ /** @internal */
4711
+ async connect(url, token) {
4712
+ await this.room.connect(url, token);
4713
+ this._status = "ready";
4714
+ this.emit("ready");
4715
+ }
4716
+ subscribe(player) {
4717
+ if (this._player) this._player.removeSubscriber(this);
4718
+ this._player = player;
4719
+ player.addSubscriber(this);
4720
+ }
4721
+ unsubscribe() {
4722
+ this._player?.removeSubscriber(this);
4723
+ this._player = null;
4724
+ }
4725
+ async _feedStream(stream) {
4726
+ if (!this._audioSource) {
4727
+ this._audioSource = new import_rtc_node.AudioSource(SAMPLE_RATE, CHANNELS, SAMPLES_PER_FRAME);
4728
+ this._audioTrack = import_rtc_node.LocalAudioTrack.createAudioTrack("audio", this._audioSource);
4729
+ const options = new import_rtc_node.TrackPublishOptions();
4730
+ options.source = import_rtc_node.TrackSource.SOURCE_MICROPHONE;
4731
+ if (!this.room.localParticipant) {
4732
+ throw new Error("Not connected to a room");
4733
+ }
4734
+ await this.room.localParticipant.publishTrack(this._audioTrack, options);
4735
+ }
4736
+ let leftover = Buffer.alloc(0);
4737
+ for await (const chunk of stream) {
4738
+ const buf = Buffer.concat([leftover, chunk]);
4739
+ let offset = 0;
4740
+ while (offset + BYTES_PER_FRAME <= buf.length) {
4741
+ const slice = buf.subarray(offset, offset + BYTES_PER_FRAME);
4742
+ const tmp = slice.buffer.slice(slice.byteOffset, slice.byteOffset + slice.byteLength);
4743
+ const pcm = new Int16Array(tmp);
4744
+ await this._audioSource.captureFrame(new import_rtc_node.AudioFrame(pcm, SAMPLE_RATE, CHANNELS, SAMPLES_PER_FRAME));
4745
+ offset += BYTES_PER_FRAME;
4746
+ }
4747
+ leftover = buf.subarray(offset);
4748
+ }
4749
+ }
4750
+ async disconnect() {
4751
+ this._status = "disconnecting";
4752
+ this.unsubscribe();
4753
+ if (this._audioTrack) {
4754
+ await this._audioTrack.close();
4755
+ this._audioTrack = null;
4756
+ this._audioSource = null;
4757
+ }
4758
+ await this.room.disconnect();
4759
+ }
4760
+ };
4761
+
4762
+ // src/voice/VoiceManager.ts
4763
+ var VoiceManager = class {
4764
+ connections = /* @__PURE__ */ new Map();
4765
+ client;
4766
+ constructor(client) {
4767
+ this.client = client;
4768
+ }
4769
+ async join(channelId, guildId) {
4770
+ const existing = this.connections.get(channelId);
4771
+ if (existing?.status === "ready") return existing;
4772
+ const { token, url } = await this.client.rest.post(`/channels/${channelId}/join_call`);
4773
+ const connection = new VoiceConnection(channelId, guildId);
4774
+ this.connections.set(channelId, connection);
4775
+ connection.once("disconnect", () => this.connections.delete(channelId));
4776
+ await connection.connect(url, token);
4777
+ return connection;
4778
+ }
4779
+ get(channelId) {
4780
+ return this.connections.get(channelId);
4781
+ }
4782
+ async leave(channelId) {
4783
+ await this.connections.get(channelId)?.disconnect();
4784
+ }
4785
+ async leaveAll() {
4786
+ await Promise.all([...this.connections.keys()].map((id) => this.leave(id)));
4787
+ }
4788
+ };
4789
+
4790
+ // src/voice/AudioPlayer.ts
4791
+ var import_node_events2 = require("events");
4792
+ var AudioPlayer = class extends import_node_events2.EventEmitter {
4793
+ _status = "idle";
4794
+ _resource = null;
4795
+ /** Registered VoiceConnections subscribed to this player */
4796
+ subscribers = /* @__PURE__ */ new Set();
4797
+ get status() {
4798
+ return this._status;
4799
+ }
4800
+ get resource() {
4801
+ return this._resource;
4802
+ }
4803
+ play(resource) {
4804
+ this.transition("buffering");
4805
+ this._resource = resource;
4806
+ resource.stream.once("readable", () => {
4807
+ this.transition("playing");
4808
+ this.feed();
4809
+ });
4810
+ resource.stream.once("end", () => {
4811
+ this._resource = null;
4812
+ this.transition("idle");
4813
+ this.emit("idle");
4814
+ });
4815
+ resource.stream.once("error", (err) => {
4816
+ this._resource = null;
4817
+ this.transition("idle");
4818
+ this.emit("error", err);
4819
+ });
4820
+ }
4821
+ pause() {
4822
+ if (this._status !== "playing") return;
4823
+ this._resource?.stream.pause();
4824
+ this.transition("paused");
4825
+ }
4826
+ resume() {
4827
+ if (this._status !== "paused") return;
4828
+ this._resource?.stream.resume();
4829
+ this.transition("playing");
4830
+ }
4831
+ stop() {
4832
+ this._resource?.stream.destroy();
4833
+ this._resource = null;
4834
+ this.transition("stopped");
4835
+ this.transition("idle");
4836
+ this.emit("idle");
4837
+ }
4838
+ /** @internal */
4839
+ addSubscriber(conn) {
4840
+ this.subscribers.add(conn);
4841
+ }
4842
+ /** @internal */
4843
+ removeSubscriber(conn) {
4844
+ this.subscribers.delete(conn);
4845
+ }
4846
+ feed() {
4847
+ if (!this._resource) return;
4848
+ for (const conn of this.subscribers) {
4849
+ conn._feedStream(this._resource.stream);
4850
+ }
4851
+ }
4852
+ transition(next) {
4853
+ const prev = this._status;
4854
+ this._status = next;
4855
+ this.emit("stateChange", prev, next);
4856
+ }
4857
+ };
4858
+
4859
+ // src/voice/AudioResource.ts
4860
+ var import_node_stream = require("stream");
4861
+ var import_node_child_process = require("child_process");
4862
+ var import_node_stream2 = require("stream");
4863
+ var import_node_fs = require("fs");
4864
+ var AudioResource = class _AudioResource {
4865
+ stream;
4866
+ constructor(stream) {
4867
+ this.stream = stream;
4868
+ }
4869
+ static from(source, options = {}) {
4870
+ if (typeof source === "string" && !source.startsWith("http") && !(0, import_node_fs.existsSync)(source)) {
4871
+ throw new Error(`Audio file not found: ${source}`);
4872
+ }
4873
+ const { volume = 1, inputType } = options;
4874
+ const args = [
4875
+ ...inputType ? ["-f", inputType] : [],
4876
+ "-i",
4877
+ typeof source === "string" ? source : "pipe:0",
4878
+ "-af",
4879
+ `volume=${volume}`,
4880
+ "-ar",
4881
+ "48000",
4882
+ "-ac",
4883
+ "2",
4884
+ "-f",
4885
+ "s16le",
4886
+ "-acodec",
4887
+ "pcm_s16le",
4888
+ "pipe:1"
4889
+ ];
4890
+ const ffmpeg = (0, import_node_child_process.spawn)("ffmpeg", args, { stdio: ["pipe", "pipe", "ignore"] });
4891
+ if (source instanceof import_node_stream.Readable) {
4892
+ source.pipe(ffmpeg.stdin);
4893
+ source.once("error", () => ffmpeg.kill());
4894
+ }
4895
+ ffmpeg.stdin?.on("error", () => {
4896
+ });
4897
+ const pass = new import_node_stream2.PassThrough();
4898
+ ffmpeg.stdout.pipe(pass);
4899
+ ffmpeg.once("error", (err) => pass.destroy(err));
4900
+ ffmpeg.once("close", (code) => {
4901
+ if (code !== 0 && code !== null) {
4902
+ pass.destroy(new Error(`ffmpeg exited with code ${code}`));
4903
+ }
4904
+ });
4905
+ return new _AudioResource(pass);
4906
+ }
4907
+ };
4908
+
4432
4909
  // src/client/Client.ts
4433
4910
  var Client = class extends import_events2.EventEmitter {
4434
4911
  rest;
@@ -4440,6 +4917,7 @@ var Client = class extends import_events2.EventEmitter {
4440
4917
  emojis;
4441
4918
  user = null;
4442
4919
  options;
4920
+ voice;
4443
4921
  constructor(options = {}) {
4444
4922
  super({ captureRejections: true });
4445
4923
  this.options = options;
@@ -4449,6 +4927,7 @@ var Client = class extends import_events2.EventEmitter {
4449
4927
  this.servers = new ServerManager(this, options.cacheLimits?.servers);
4450
4928
  this.users = new UserManager(this, options.cacheLimits?.users);
4451
4929
  this.emojis = new EmojiManager(this, void 0, options.cacheLimits?.emojis);
4930
+ this.voice = new VoiceManager(this);
4452
4931
  this.sweepers = new SweeperManager(this, options.sweepers ?? {});
4453
4932
  }
4454
4933
  /**
@@ -4538,12 +5017,15 @@ var EmbedBuilder = class {
4538
5017
  };
4539
5018
 
4540
5019
  // src/index.ts
5020
+ var import_ulid8 = require("ulid");
4541
5021
  var API = __toESM(require("stoat-api"), 1);
4542
5022
  // Annotate the CommonJS export names for ESM import in node:
4543
5023
  0 && (module.exports = {
4544
5024
  API,
4545
5025
  Attachment,
4546
5026
  AttachmentBuilder,
5027
+ AudioPlayer,
5028
+ AudioResource,
4547
5029
  Base,
4548
5030
  BaseChannel,
4549
5031
  BitField,
@@ -4578,6 +5060,9 @@ var API = __toESM(require("stoat-api"), 1);
4578
5060
  TextChannel,
4579
5061
  UnknownChannel,
4580
5062
  User,
4581
- UserManager
5063
+ UserManager,
5064
+ VoiceConnection,
5065
+ VoiceManager,
5066
+ decodeTime
4582
5067
  });
4583
5068
  //# sourceMappingURL=index.cjs.map