lunibee 0.1.8 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +2 -0
  2. package/dist/builders/components.d.ts +30 -2
  3. package/dist/builders/embed.d.ts +7 -7
  4. package/dist/builders/index.d.ts +1 -1
  5. package/dist/builders/index.js +110 -18
  6. package/dist/builders/index.js.map +6 -6
  7. package/dist/collection/index.d.ts +68 -1
  8. package/dist/collection/index.js +334 -1
  9. package/dist/collection/index.js.map +3 -3
  10. package/dist/core/collector.d.ts +13 -0
  11. package/dist/core/events.d.ts +29 -3
  12. package/dist/core/index.d.ts +25 -9
  13. package/dist/core/index.js +1745 -134
  14. package/dist/core/index.js.map +30 -26
  15. package/dist/core/permissions.d.ts +48 -0
  16. package/dist/index.js +2102 -362
  17. package/dist/index.js.map +36 -34
  18. package/dist/managers/advanced.d.ts +116 -0
  19. package/dist/managers/base.d.ts +13 -2
  20. package/dist/managers/emoji.d.ts +1 -1
  21. package/dist/managers/guild-resources.d.ts +22 -2
  22. package/dist/managers/guild.d.ts +31 -3
  23. package/dist/managers/index.d.ts +38 -6
  24. package/dist/managers/index.js +996 -160
  25. package/dist/managers/index.js.map +20 -18
  26. package/dist/managers/member.d.ts +13 -12
  27. package/dist/managers/message.d.ts +21 -4
  28. package/dist/rest/errors.d.ts +33 -0
  29. package/dist/rest/index.d.ts +1 -1
  30. package/dist/rest/index.js +52 -6
  31. package/dist/rest/index.js.map +5 -5
  32. package/dist/rest/routes.d.ts +20 -0
  33. package/dist/sharding/index.d.ts +29 -0
  34. package/dist/sharding/index.js +99 -15
  35. package/dist/sharding/index.js.map +8 -8
  36. package/dist/structures/base.d.ts +38 -0
  37. package/dist/structures/index.d.ts +29 -0
  38. package/dist/structures/index.js +208 -46
  39. package/dist/structures/index.js.map +13 -12
  40. package/dist/structures/interactions.d.ts +51 -1
  41. package/dist/structures/options.d.ts +2 -0
  42. package/dist/structures/resources.d.ts +29 -3
  43. package/dist/types/gateway.d.ts +16 -0
  44. package/dist/types/index.d.ts +67 -1
  45. package/dist/types/index.js.map +3 -3
  46. package/dist/utils/args.d.ts +79 -0
  47. package/dist/utils/index.d.ts +1 -0
  48. package/dist/utils/index.js +190 -2
  49. package/dist/utils/index.js.map +5 -4
  50. package/dist/voice/index.d.ts +3 -0
  51. package/dist/voice/index.js +15 -1
  52. package/dist/voice/index.js.map +3 -3
  53. package/dist/ws/index.js +13 -5
  54. package/dist/ws/index.js.map +6 -6
  55. package/package.json +14 -14
package/dist/index.js CHANGED
@@ -53,8 +53,11 @@ var Permission = {
53
53
  createEvents: 1n << 44n,
54
54
  useExternalSounds: 1n << 45n,
55
55
  sendVoiceMessages: 1n << 46n,
56
+ setVoiceChannelStatus: 1n << 48n,
56
57
  sendPolls: 1n << 49n,
57
- useExternalApps: 1n << 50n
58
+ useExternalApps: 1n << 50n,
59
+ pinMessages: 1n << 51n,
60
+ bypassSlowmode: 1n << 52n
58
61
  };
59
62
  var Permissions = {
60
63
  CreateInstantInvite: 1n << 0n,
@@ -104,8 +107,11 @@ var Permissions = {
104
107
  CreateEvents: 1n << 44n,
105
108
  UseExternalSounds: 1n << 45n,
106
109
  SendVoiceMessages: 1n << 46n,
110
+ SetVoiceChannelStatus: 1n << 48n,
107
111
  SendPolls: 1n << 49n,
108
- UseExternalApps: 1n << 50n
112
+ UseExternalApps: 1n << 50n,
113
+ PinMessages: 1n << 51n,
114
+ BypassSlowmode: 1n << 52n
109
115
  };
110
116
  var PermissionFlagsBits = {
111
117
  CreateInstantInvite: 1n << 0n,
@@ -155,8 +161,11 @@ var PermissionFlagsBits = {
155
161
  CreateEvents: 1n << 44n,
156
162
  UseExternalSounds: 1n << 45n,
157
163
  SendVoiceMessages: 1n << 46n,
164
+ SetVoiceChannelStatus: 1n << 48n,
158
165
  SendPolls: 1n << 49n,
159
- UseExternalApps: 1n << 50n
166
+ UseExternalApps: 1n << 50n,
167
+ PinMessages: 1n << 51n,
168
+ BypassSlowmode: 1n << 52n
160
169
  };
161
170
 
162
171
  class PermissionSet {
@@ -358,6 +367,10 @@ class PermissionSet {
358
367
  }
359
368
  return false;
360
369
  }
370
+ missing(...permissions) {
371
+ const wanted = new PermissionSet(permissions);
372
+ return wanted.toArray().filter((name) => !this.has(name));
373
+ }
361
374
  add(...permissions) {
362
375
  let bitfield = this.bitfield;
363
376
  for (let i = 0;i < permissions.length; i++) {
@@ -383,6 +396,11 @@ class PermissionSet {
383
396
  toArray() {
384
397
  return Object.keys(Permission).filter((permission) => this.has(permission));
385
398
  }
399
+ static #renamed = {
400
+ ManageEmojisAndStickers: "ManageGuildExpressions",
401
+ ManageEmojis: "ManageGuildExpressions",
402
+ UseSlashCommands: "UseApplicationCommands"
403
+ };
386
404
  #resolve(permission) {
387
405
  if (typeof permission === "bigint")
388
406
  return permission;
@@ -397,6 +415,9 @@ class PermissionSet {
397
415
  return bit;
398
416
  }
399
417
  if (typeof permission === "string") {
418
+ const renamed = PermissionSet.#renamed[permission];
419
+ if (renamed)
420
+ return this.#resolve(renamed);
400
421
  if (permission in Permission)
401
422
  return Permission[permission];
402
423
  if (permission in Permissions)
@@ -419,6 +440,35 @@ class PermissionsBitField extends PermissionSet {
419
440
  super(value);
420
441
  }
421
442
  }
443
+ var ALL_PERMISSIONS = Object.values(Permission).reduce((bits, bit) => bits | bit, 0n);
444
+ var bits = (value) => new PermissionSet(value).bitfield;
445
+ function computePermissions(context) {
446
+ if (context.ownerId !== undefined && context.ownerId === context.memberId)
447
+ return new PermissionSet(ALL_PERMISSIONS);
448
+ const roles = new Map(context.roles.map((role) => [role.id, role]));
449
+ let base = bits(roles.get(context.guildId)?.permissions ?? 0n);
450
+ for (const id of context.memberRoleIds)
451
+ base |= bits(roles.get(id)?.permissions ?? 0n);
452
+ if (base & Permission.administrator)
453
+ return new PermissionSet(ALL_PERMISSIONS);
454
+ const overwrites = context.overwrites ?? [];
455
+ const everyone = overwrites.find((o) => o.id === context.guildId);
456
+ if (everyone)
457
+ base = base & ~bits(everyone.deny) | bits(everyone.allow);
458
+ const memberRoles = new Set(context.memberRoleIds);
459
+ let allow = 0n;
460
+ let deny = 0n;
461
+ for (const overwrite of overwrites)
462
+ if (overwrite.type === 0 /* Role */ && overwrite.id !== context.guildId && memberRoles.has(overwrite.id)) {
463
+ allow |= bits(overwrite.allow);
464
+ deny |= bits(overwrite.deny);
465
+ }
466
+ base = base & ~deny | allow;
467
+ const member = overwrites.find((o) => o.type === 1 /* Member */ && o.id === context.memberId);
468
+ if (member)
469
+ base = base & ~bits(member.deny) | bits(member.allow);
470
+ return new PermissionSet(base);
471
+ }
422
472
  // packages/core/src/events.ts
423
473
  var ClientEvent;
424
474
  ((ClientEvent) => {
@@ -455,6 +505,13 @@ var ClientEvent;
455
505
  ClientEvent["GuildRoleDelete"] = "guildRoleDelete";
456
506
  ClientEvent["GuildEmojisUpdate"] = "guildEmojisUpdate";
457
507
  ClientEvent["GuildStickersUpdate"] = "guildStickersUpdate";
508
+ ClientEvent["EntitlementCreate"] = "entitlementCreate";
509
+ ClientEvent["EntitlementUpdate"] = "entitlementUpdate";
510
+ ClientEvent["EntitlementDelete"] = "entitlementDelete";
511
+ ClientEvent["SoundboardSoundCreate"] = "soundboardSoundCreate";
512
+ ClientEvent["SoundboardSoundUpdate"] = "soundboardSoundUpdate";
513
+ ClientEvent["SoundboardSoundDelete"] = "soundboardSoundDelete";
514
+ ClientEvent["SoundboardSoundsUpdate"] = "soundboardSoundsUpdate";
458
515
  ClientEvent["GuildIntegrationsUpdate"] = "guildIntegrationsUpdate";
459
516
  ClientEvent["GuildScheduledEventCreate"] = "guildScheduledEventCreate";
460
517
  ClientEvent["GuildScheduledEventUpdate"] = "guildScheduledEventUpdate";
@@ -497,6 +554,9 @@ class Collector extends EventEmitter {
497
554
  endReason;
498
555
  totalProcessed = 0;
499
556
  #timeoutTimer;
557
+ #idleTimer;
558
+ #onAbort = () => this.stop("abort");
559
+ #cleanup = [];
500
560
  constructor(options = {}) {
501
561
  super();
502
562
  this.options = options;
@@ -505,6 +565,27 @@ class Collector extends EventEmitter {
505
565
  this.stop("time");
506
566
  }, options.time);
507
567
  }
568
+ this.#resetIdle();
569
+ if (options.signal?.aborted)
570
+ this.stop("abort");
571
+ else
572
+ options.signal?.addEventListener("abort", this.#onAbort, {
573
+ once: true
574
+ });
575
+ }
576
+ onDispose(cleanup) {
577
+ if (this.ended)
578
+ cleanup();
579
+ else
580
+ this.#cleanup.push(cleanup);
581
+ return this;
582
+ }
583
+ #resetIdle() {
584
+ if (!this.options.idle || this.options.idle <= 0)
585
+ return;
586
+ if (this.#idleTimer)
587
+ clearTimeout(this.#idleTimer);
588
+ this.#idleTimer = setTimeout(() => this.stop("idle"), this.options.idle);
508
589
  }
509
590
  async handle(key, item) {
510
591
  if (this.ended)
@@ -522,6 +603,7 @@ class Collector extends EventEmitter {
522
603
  return false;
523
604
  }
524
605
  this.collected.set(key, item);
606
+ this.#resetIdle();
525
607
  this.emit("collect", item);
526
608
  if (this.options.max && this.collected.size >= this.options.max) {
527
609
  this.stop("limit");
@@ -540,9 +622,53 @@ class Collector extends EventEmitter {
540
622
  this.endReason = reason;
541
623
  if (this.#timeoutTimer)
542
624
  clearTimeout(this.#timeoutTimer);
625
+ if (this.#idleTimer)
626
+ clearTimeout(this.#idleTimer);
627
+ this.options.signal?.removeEventListener("abort", this.#onAbort);
628
+ for (const cleanup of this.#cleanup.splice(0)) {
629
+ try {
630
+ cleanup();
631
+ } catch {}
632
+ }
543
633
  this.emit("end", this.collected, reason);
544
634
  this.removeAllListeners();
545
635
  }
636
+ wait() {
637
+ if (this.ended)
638
+ return Promise.resolve(this.collected);
639
+ return new Promise((resolve) => this.once("end", (collected) => resolve(collected)));
640
+ }
641
+ async* [Symbol.asyncIterator]() {
642
+ const queue = [];
643
+ let wake;
644
+ const onCollect = (item) => {
645
+ queue.push(item);
646
+ wake?.();
647
+ };
648
+ const onEnd = () => wake?.();
649
+ if (!this.ended) {
650
+ this.on("collect", onCollect);
651
+ this.on("end", onEnd);
652
+ }
653
+ try {
654
+ for (;; ) {
655
+ if (queue.length > 0) {
656
+ yield queue.shift();
657
+ continue;
658
+ }
659
+ if (this.ended)
660
+ return;
661
+ await new Promise((resolve) => wake = resolve);
662
+ wake = undefined;
663
+ }
664
+ } finally {
665
+ this.off("collect", onCollect);
666
+ this.off("end", onEnd);
667
+ }
668
+ }
669
+ [Symbol.dispose]() {
670
+ this.stop("disposed");
671
+ }
546
672
  next() {
547
673
  return new Promise((resolve, reject) => {
548
674
  if (this.ended) {
@@ -858,7 +984,340 @@ class Cache {
858
984
  }
859
985
 
860
986
  // packages/collection/src/index.ts
987
+ class RecencyList {
988
+ #nodes = new Map;
989
+ #oldest;
990
+ #newest;
991
+ get size() {
992
+ return this.#nodes.size;
993
+ }
994
+ oldest() {
995
+ return this.#oldest?.key;
996
+ }
997
+ touch(key) {
998
+ const node = this.#nodes.get(key);
999
+ if (node)
1000
+ return this.#moveNewest(node);
1001
+ const created = { key, older: this.#newest };
1002
+ if (this.#newest)
1003
+ this.#newest.newer = created;
1004
+ else
1005
+ this.#oldest = created;
1006
+ this.#newest = created;
1007
+ this.#nodes.set(key, created);
1008
+ }
1009
+ promote(key) {
1010
+ const node = this.#nodes.get(key);
1011
+ if (node)
1012
+ this.#moveNewest(node);
1013
+ }
1014
+ delete(key) {
1015
+ const node = this.#nodes.get(key);
1016
+ if (!node)
1017
+ return false;
1018
+ this.#unlink(node);
1019
+ this.#nodes.delete(key);
1020
+ return true;
1021
+ }
1022
+ clear() {
1023
+ this.#nodes.clear();
1024
+ this.#oldest = this.#newest = undefined;
1025
+ }
1026
+ #unlink(node) {
1027
+ if (node.older)
1028
+ node.older.newer = node.newer;
1029
+ else
1030
+ this.#oldest = node.newer;
1031
+ if (node.newer)
1032
+ node.newer.older = node.older;
1033
+ else
1034
+ this.#newest = node.older;
1035
+ node.older = node.newer = undefined;
1036
+ }
1037
+ #moveNewest(node) {
1038
+ if (node === this.#newest)
1039
+ return;
1040
+ this.#unlink(node);
1041
+ node.older = this.#newest;
1042
+ if (this.#newest)
1043
+ this.#newest.newer = node;
1044
+ else
1045
+ this.#oldest = node;
1046
+ this.#newest = node;
1047
+ }
1048
+ }
1049
+ function assertTTL(ttl) {
1050
+ if (ttl !== undefined && (!Number.isFinite(ttl) || ttl <= 0))
1051
+ throw new RangeError("TTL must be a positive number, or omitted.");
1052
+ }
1053
+
861
1054
  class Collection extends Map {
1055
+ #ttl;
1056
+ #maxSize;
1057
+ #onEvict;
1058
+ #expiry = new Map;
1059
+ #lru = new RecencyList;
1060
+ #stats = {
1061
+ hits: 0,
1062
+ misses: 0,
1063
+ expired: 0,
1064
+ evicted: 0
1065
+ };
1066
+ #heap = [];
1067
+ #timer;
1068
+ #armedFor = Infinity;
1069
+ constructor(entries, options = {}) {
1070
+ super();
1071
+ assertTTL(options.ttl);
1072
+ if (options.maxSize !== undefined && (!Number.isInteger(options.maxSize) || options.maxSize <= 0))
1073
+ throw new RangeError("maxSize must be a positive integer.");
1074
+ this.#ttl = options.ttl;
1075
+ this.#maxSize = options.maxSize;
1076
+ this.#onEvict = options.onEvict;
1077
+ if (entries)
1078
+ for (const [key, value] of entries)
1079
+ this.set(key, value);
1080
+ }
1081
+ set(key, value, ttl) {
1082
+ assertTTL(ttl);
1083
+ const window = ttl ?? this.#ttl;
1084
+ if (this.#maxSize !== undefined) {
1085
+ this.#lru.touch(key);
1086
+ }
1087
+ super.set(key, value);
1088
+ if (window !== undefined)
1089
+ this.#schedule(key, window);
1090
+ else if (this.#expiry.size > 0)
1091
+ this.#expiry.delete(key);
1092
+ this.#enforceCap();
1093
+ return this;
1094
+ }
1095
+ setWithoutTTL(key, value) {
1096
+ if (this.#expiry.size > 0)
1097
+ this.#expiry.delete(key);
1098
+ if (this.#lru.size > 0)
1099
+ this.#lru.delete(key);
1100
+ super.set(key, value);
1101
+ return this;
1102
+ }
1103
+ get(key) {
1104
+ if (this.#expireIfDue(key)) {
1105
+ this.#stats.misses++;
1106
+ return;
1107
+ }
1108
+ const value = super.get(key);
1109
+ if (value === undefined && !super.has(key)) {
1110
+ this.#stats.misses++;
1111
+ return;
1112
+ }
1113
+ this.#stats.hits++;
1114
+ const expiry = this.#expiry.get(key);
1115
+ if (expiry)
1116
+ expiry.deadline = Date.now() + expiry.window;
1117
+ this.#lru.promote(key);
1118
+ return value;
1119
+ }
1120
+ peek(key) {
1121
+ if (!this.#expireIfDue(key) && super.has(key)) {
1122
+ this.#stats.hits++;
1123
+ return super.get(key);
1124
+ }
1125
+ this.#stats.misses++;
1126
+ return;
1127
+ }
1128
+ get stats() {
1129
+ return { ...this.#stats };
1130
+ }
1131
+ has(key) {
1132
+ return !this.#expireIfDue(key) && super.has(key);
1133
+ }
1134
+ delete(key) {
1135
+ if (this.#expireIfDue(key))
1136
+ return false;
1137
+ this.#expiry.delete(key);
1138
+ this.#lru.delete(key);
1139
+ return super.delete(key);
1140
+ }
1141
+ clear() {
1142
+ super.clear();
1143
+ this.#expiry.clear();
1144
+ this.#lru.clear();
1145
+ this.#heap.length = 0;
1146
+ if (this.#timer)
1147
+ clearTimeout(this.#timer);
1148
+ this.#timer = undefined;
1149
+ this.#armedFor = Infinity;
1150
+ }
1151
+ get size() {
1152
+ this.purge();
1153
+ return super.size;
1154
+ }
1155
+ entries() {
1156
+ this.purge();
1157
+ return super.entries();
1158
+ }
1159
+ keys() {
1160
+ this.purge();
1161
+ return super.keys();
1162
+ }
1163
+ values() {
1164
+ this.purge();
1165
+ return super.values();
1166
+ }
1167
+ [Symbol.iterator]() {
1168
+ return this.entries();
1169
+ }
1170
+ forEach(callback, thisArg) {
1171
+ this.purge();
1172
+ super.forEach(callback, thisArg);
1173
+ }
1174
+ ttlRemaining(key) {
1175
+ if (this.#expireIfDue(key))
1176
+ return;
1177
+ const expiry = this.#expiry.get(key);
1178
+ return expiry && Math.max(0, expiry.deadline - Date.now());
1179
+ }
1180
+ purge() {
1181
+ if (this.#expiry.size === 0)
1182
+ return 0;
1183
+ const now = Date.now();
1184
+ let removed = 0;
1185
+ const dropped = [];
1186
+ while (this.#nextDeadline() <= now) {
1187
+ const due = this.#heapPop();
1188
+ dropped.push([due.key, super.get(due.key)]);
1189
+ this.#remove(due.key);
1190
+ removed++;
1191
+ }
1192
+ this.#stats.expired += removed;
1193
+ this.#rearm();
1194
+ for (const [key, value] of dropped)
1195
+ this.#notify(key, value, "expired");
1196
+ return removed;
1197
+ }
1198
+ #expireIfDue(key) {
1199
+ const expiry = this.#expiry.get(key);
1200
+ if (!expiry || expiry.deadline > Date.now())
1201
+ return false;
1202
+ const value = super.get(key);
1203
+ this.#remove(key);
1204
+ this.#stats.expired++;
1205
+ this.#notify(key, value, "expired");
1206
+ return true;
1207
+ }
1208
+ #remove(key) {
1209
+ this.#expiry.delete(key);
1210
+ this.#lru.delete(key);
1211
+ super.delete(key);
1212
+ }
1213
+ #notify(key, value, reason) {
1214
+ if (!this.#onEvict)
1215
+ return;
1216
+ try {
1217
+ this.#onEvict(key, value, reason);
1218
+ } catch {}
1219
+ }
1220
+ #enforceCap() {
1221
+ if (this.#maxSize === undefined)
1222
+ return;
1223
+ while (this.#lru.size > this.#maxSize) {
1224
+ const oldest = this.#lru.oldest();
1225
+ const value = super.get(oldest);
1226
+ this.#remove(oldest);
1227
+ this.#stats.evicted++;
1228
+ this.#notify(oldest, value, "evicted");
1229
+ }
1230
+ }
1231
+ #schedule(key, window) {
1232
+ const deadline = Date.now() + window;
1233
+ const expiry = this.#expiry.get(key);
1234
+ if (expiry) {
1235
+ expiry.deadline = deadline;
1236
+ expiry.window = window;
1237
+ if (deadline >= expiry.filed)
1238
+ return;
1239
+ expiry.filed = deadline;
1240
+ } else
1241
+ this.#expiry.set(key, { deadline, window, filed: deadline });
1242
+ this.#heapPush({ key, deadline });
1243
+ if (this.#heap.length > 2 * this.#expiry.size + 8)
1244
+ this.#compact();
1245
+ this.#rearm();
1246
+ }
1247
+ #nextDeadline() {
1248
+ for (;; ) {
1249
+ const top = this.#heap[0];
1250
+ if (top === undefined)
1251
+ return Infinity;
1252
+ const expiry = this.#expiry.get(top.key);
1253
+ if (!expiry || expiry.filed !== top.deadline) {
1254
+ this.#heapPop();
1255
+ continue;
1256
+ }
1257
+ if (expiry.deadline === top.deadline)
1258
+ return top.deadline;
1259
+ this.#heapPop();
1260
+ expiry.filed = expiry.deadline;
1261
+ this.#heapPush({ key: top.key, deadline: expiry.deadline });
1262
+ }
1263
+ }
1264
+ #compact() {
1265
+ const live = this.#heap.filter((record) => this.#expiry.get(record.key)?.filed === record.deadline);
1266
+ this.#heap.length = 0;
1267
+ for (const record of live)
1268
+ this.#heapPush(record);
1269
+ }
1270
+ #rearm() {
1271
+ const deadline = this.#nextDeadline();
1272
+ if (this.#timer !== undefined && deadline >= this.#armedFor)
1273
+ return;
1274
+ if (this.#timer)
1275
+ clearTimeout(this.#timer);
1276
+ this.#timer = undefined;
1277
+ this.#armedFor = deadline;
1278
+ if (deadline === Infinity)
1279
+ return;
1280
+ this.#timer = setTimeout(() => {
1281
+ this.#timer = undefined;
1282
+ this.#armedFor = Infinity;
1283
+ this.purge();
1284
+ }, Math.max(0, deadline - Date.now()));
1285
+ this.#timer.unref?.();
1286
+ }
1287
+ #heapPush(record) {
1288
+ const heap = this.#heap;
1289
+ heap.push(record);
1290
+ let i = heap.length - 1;
1291
+ while (i > 0) {
1292
+ const parent = i - 1 >> 1;
1293
+ if (heap[parent].deadline <= heap[i].deadline)
1294
+ break;
1295
+ [heap[parent], heap[i]] = [heap[i], heap[parent]];
1296
+ i = parent;
1297
+ }
1298
+ }
1299
+ #heapPop() {
1300
+ const heap = this.#heap;
1301
+ const top = heap[0];
1302
+ const last = heap.pop();
1303
+ if (top === undefined || heap.length === 0)
1304
+ return top;
1305
+ heap[0] = last;
1306
+ for (let i = 0;; ) {
1307
+ const left = 2 * i + 1;
1308
+ const right = left + 1;
1309
+ let smallest = i;
1310
+ if (left < heap.length && heap[left].deadline < heap[smallest].deadline)
1311
+ smallest = left;
1312
+ if (right < heap.length && heap[right].deadline < heap[smallest].deadline)
1313
+ smallest = right;
1314
+ if (smallest === i)
1315
+ break;
1316
+ [heap[smallest], heap[i]] = [heap[i], heap[smallest]];
1317
+ i = smallest;
1318
+ }
1319
+ return top;
1320
+ }
862
1321
  first() {
863
1322
  for (const value of this.values())
864
1323
  return value;
@@ -1083,11 +1542,40 @@ class Manager {
1083
1542
  has(id) {
1084
1543
  return this.cache.has(id);
1085
1544
  }
1545
+ #inflight = new Map;
1546
+ fetchOnce(id, load, store = (value) => {
1547
+ this.set(id, value);
1548
+ return value;
1549
+ }) {
1550
+ const pending = this.#inflight.get(id);
1551
+ if (pending)
1552
+ return pending.promise;
1553
+ const entry = {
1554
+ promise: new Promise((resolve) => resolve(load())),
1555
+ dirty: false
1556
+ };
1557
+ this.#inflight.set(id, entry);
1558
+ entry.promise = entry.promise.then((value) => {
1559
+ this.#inflight.delete(id);
1560
+ return entry.dirty ? this.get(id) ?? value : store(value);
1561
+ }, (error) => {
1562
+ this.#inflight.delete(id);
1563
+ throw error;
1564
+ });
1565
+ return entry.promise;
1566
+ }
1567
+ #markDirty(id) {
1568
+ const pending = this.#inflight.get(id);
1569
+ if (pending)
1570
+ pending.dirty = true;
1571
+ }
1086
1572
  set(id, value) {
1087
- this.cache.set(id, value);
1573
+ this.#markDirty(id);
1574
+ this.cache.setWithoutTTL(id, value);
1088
1575
  return this;
1089
1576
  }
1090
1577
  delete(id) {
1578
+ this.#markDirty(id);
1091
1579
  return this.cache.delete(id);
1092
1580
  }
1093
1581
  clear() {
@@ -1123,16 +1611,20 @@ class ResourceManager extends Manager {
1123
1611
  async resolve(id) {
1124
1612
  return this.get(id) ?? this.fetch(id);
1125
1613
  }
1126
- async fetch(id) {
1127
- const resource = await this.#fetcher(id);
1128
- this.set(id, resource);
1129
- return resource;
1614
+ fetch(id) {
1615
+ return this.fetchOnce(id, () => this.#fetcher(id));
1130
1616
  }
1131
1617
  async fetchMany(ids) {
1132
1618
  return Promise.all([...ids].map((id) => this.resolve(id)));
1133
1619
  }
1134
1620
  upsert(resource) {
1135
1621
  const key = this.#key(resource);
1622
+ const existing = this.get(key);
1623
+ if (existing !== undefined && existing !== resource && typeof existing === "object" && existing !== null) {
1624
+ Object.assign(existing, resource);
1625
+ this.set(key, existing);
1626
+ return existing;
1627
+ }
1136
1628
  this.set(key, resource);
1137
1629
  return resource;
1138
1630
  }
@@ -1143,7 +1635,7 @@ class ResourceManager extends Manager {
1143
1635
  // packages/rest/package.json
1144
1636
  var package_default = {
1145
1637
  name: "@lunibee/rest",
1146
- version: "0.1.8",
1638
+ version: "0.2.1",
1147
1639
  type: "module",
1148
1640
  module: "./src/index.ts",
1149
1641
  types: "./src/index.ts",
@@ -1203,7 +1695,29 @@ class MemoryRateLimitStore {
1203
1695
  }
1204
1696
 
1205
1697
  // packages/rest/src/errors.ts
1698
+ function kindFromStatus(status) {
1699
+ if (status === 429)
1700
+ return "rateLimited";
1701
+ if (status === 401)
1702
+ return "authentication";
1703
+ if (status === 403)
1704
+ return "permission";
1705
+ if (status === 404)
1706
+ return "notFound";
1707
+ if (status === 400 || status === 422)
1708
+ return "validation";
1709
+ if (status >= 500)
1710
+ return "server";
1711
+ if (status === 0)
1712
+ return "network";
1713
+ return "client";
1714
+ }
1715
+ function redactPath(path) {
1716
+ return path.replace(/^(\/webhooks\/[^/?]+\/)[^/?]+/, "$1:token").replace(/^(\/interactions\/[^/?]+\/)[^/?]+/, "$1:token");
1717
+ }
1718
+
1206
1719
  class RESTError extends Error {
1720
+ kind;
1207
1721
  status;
1208
1722
  code;
1209
1723
  errors;
@@ -1213,14 +1727,18 @@ class RESTError extends Error {
1213
1727
  super(message, options.cause === undefined ? undefined : { cause: options.cause });
1214
1728
  this.name = "RESTError";
1215
1729
  this.status = status;
1730
+ this.kind = options.kind ?? kindFromStatus(status);
1216
1731
  this.code = code;
1217
1732
  this.errors = errors;
1218
1733
  this.method = options.method;
1219
- this.path = options.path;
1734
+ this.path = options.path === undefined ? undefined : redactPath(options.path);
1735
+ }
1736
+ get retryable() {
1737
+ return this.kind === "rateLimited" || this.kind === "server" || this.kind === "network" || this.kind === "timeout";
1220
1738
  }
1221
1739
  }
1222
1740
  function abortError(path, reason) {
1223
- return new RESTError(reason instanceof Error ? reason.message : "Discord REST request was aborted", 0, undefined, undefined, { path, cause: reason });
1741
+ return new RESTError(reason instanceof Error ? reason.message : "Discord REST request was aborted", 0, undefined, undefined, { path, cause: reason, kind: "aborted" });
1224
1742
  }
1225
1743
  async function sleep(delay, signal, path) {
1226
1744
  if (delay <= 0)
@@ -1555,8 +2073,23 @@ var Routes = {
1555
2073
  invite: (code) => `/invites/${encodeURIComponent(code)}`,
1556
2074
  guildVanity: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/vanity-url`,
1557
2075
  guildEmoji: (guildId, emojiId) => emojiId ? `/guilds/${snowflake(guildId, "Guild ID")}/emojis/${snowflake(emojiId, "Emoji ID")}` : `/guilds/${snowflake(guildId, "Guild ID")}/emojis`,
1558
- applicationEmoji: (applicationId, emojiId) => emojiId ? `/applications/${snowflake(applicationId, "Application ID")}/emojis/${snowflake(emojiId, "Emoji ID")}` : `/applications/${snowflake(applicationId, "Application ID")}/emojis`
2076
+ applicationEmoji: (applicationId, emojiId) => emojiId ? `/applications/${snowflake(applicationId, "Application ID")}/emojis/${snowflake(emojiId, "Emoji ID")}` : `/applications/${snowflake(applicationId, "Application ID")}/emojis`,
2077
+ pollExpire: (channelId, messageId) => `/channels/${snowflake(channelId, "Channel ID")}/polls/${snowflake(messageId, "Message ID")}/expire`,
2078
+ pollAnswerVoters: (channelId, messageId, answerId) => `/channels/${snowflake(channelId, "Channel ID")}/polls/${snowflake(messageId, "Message ID")}/answers/${integer(answerId, "Answer ID")}`,
2079
+ guildSticker: (guildId, stickerId) => stickerId ? `/guilds/${snowflake(guildId, "Guild ID")}/stickers/${snowflake(stickerId, "Sticker ID")}` : `/guilds/${snowflake(guildId, "Guild ID")}/stickers`,
2080
+ sendSoundboardSound: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/send-soundboard-sound`,
2081
+ soundboardDefaultSounds: () => "/soundboard-default-sounds",
2082
+ guildSoundboardSound: (guildId, soundId) => soundId ? `/guilds/${snowflake(guildId, "Guild ID")}/soundboard-sounds/${snowflake(soundId, "Sound ID")}` : `/guilds/${snowflake(guildId, "Guild ID")}/soundboard-sounds`,
2083
+ applicationSkus: (applicationId) => `/applications/${snowflake(applicationId, "Application ID")}/skus`,
2084
+ applicationEntitlement: (applicationId, entitlementId) => entitlementId ? `/applications/${snowflake(applicationId, "Application ID")}/entitlements/${snowflake(entitlementId, "Entitlement ID")}` : `/applications/${snowflake(applicationId, "Application ID")}/entitlements`,
2085
+ consumeEntitlement: (applicationId, entitlementId) => `/applications/${snowflake(applicationId, "Application ID")}/entitlements/${snowflake(entitlementId, "Entitlement ID")}/consume`,
2086
+ skuSubscription: (skuId, subscriptionId) => subscriptionId ? `/skus/${snowflake(skuId, "SKU ID")}/subscriptions/${snowflake(subscriptionId, "Subscription ID")}` : `/skus/${snowflake(skuId, "SKU ID")}/subscriptions`
1559
2087
  };
2088
+ function integer(value, field) {
2089
+ if (!Number.isInteger(value) || value < 0)
2090
+ throw new TypeError(`${field} must be a non-negative integer.`);
2091
+ return String(value);
2092
+ }
1560
2093
  function snowflake(value, field) {
1561
2094
  if (!/^\d{1,20}$/.test(value))
1562
2095
  throw new TypeError(`${field} must be a valid Discord snowflake.`);
@@ -1870,7 +2403,8 @@ class REST {
1870
2403
  throw new RESTError(failure.message, 0, undefined, undefined, {
1871
2404
  method,
1872
2405
  path,
1873
- cause: failure.cause ?? failure
2406
+ cause: failure.cause ?? failure,
2407
+ kind: failure.timedOut ? "timeout" : "network"
1874
2408
  });
1875
2409
  }
1876
2410
  this.#emit(this.#hooks.onResponse, {
@@ -1969,6 +2503,9 @@ class REST {
1969
2503
  #emit(hook, ctx) {
1970
2504
  if (!hook)
1971
2505
  return;
2506
+ const withPath = ctx;
2507
+ if (typeof withPath.path === "string")
2508
+ ctx = { ...ctx, path: redactPath(withPath.path) };
1972
2509
  Promise.resolve().then(() => hook(ctx)).catch(() => {});
1973
2510
  }
1974
2511
  }
@@ -2045,6 +2582,7 @@ class Channel extends BaseStructure {
2045
2582
  nsfw;
2046
2583
  rateLimitPerUser;
2047
2584
  position;
2585
+ permissionOverwrites;
2048
2586
  #context;
2049
2587
  constructor(data, context) {
2050
2588
  super(data.id);
@@ -2058,6 +2596,7 @@ class Channel extends BaseStructure {
2058
2596
  this.nsfw = data.nsfw;
2059
2597
  this.rateLimitPerUser = data.rate_limit_per_user;
2060
2598
  this.position = data.position;
2599
+ this.permissionOverwrites = (data.permission_overwrites ?? []).map((overwrite) => ({ ...overwrite }));
2061
2600
  this.#context = context;
2062
2601
  }
2063
2602
  sendMessage(options) {
@@ -2081,6 +2620,11 @@ class Channel extends BaseStructure {
2081
2620
  editTopic(topic) {
2082
2621
  return this.edit({ topic });
2083
2622
  }
2623
+ editPermissionOverwrite(targetId, changes, options) {
2624
+ if (!this.#context?.editPermissionOverwrite)
2625
+ throw new Error("This channel is not attached to a client.");
2626
+ return this.#context.editPermissionOverwrite(this.id, targetId, changes, options);
2627
+ }
2084
2628
  editParent(parentId) {
2085
2629
  return this.edit({ parent_id: parentId });
2086
2630
  }
@@ -2215,6 +2759,7 @@ class Guild extends BaseStructure {
2215
2759
  return this.name;
2216
2760
  }
2217
2761
  }
2762
+
2218
2763
  // packages/structures/src/resources.ts
2219
2764
  function toDateOrNull(value) {
2220
2765
  if (!value)
@@ -2230,13 +2775,15 @@ class GuildMember {
2230
2775
  roleIds;
2231
2776
  pending;
2232
2777
  joinedAt;
2233
- permissions;
2234
2778
  avatarHash;
2235
2779
  premiumSince;
2236
2780
  timedOutUntil;
2237
2781
  flags;
2238
- constructor(data) {
2782
+ #suppliedPermissions;
2783
+ #context;
2784
+ constructor(data, context) {
2239
2785
  this.user = new User(data.user);
2786
+ this.#context = context;
2240
2787
  if (!/^\d{1,20}$/.test(data.guild_id))
2241
2788
  throw new TypeError("Member guild_id must be a valid snowflake.");
2242
2789
  this.guildId = data.guild_id;
@@ -2246,12 +2793,53 @@ class GuildMember {
2246
2793
  this.joinedAt = data.joined_at ? new Date(data.joined_at) : undefined;
2247
2794
  if (this.joinedAt?.toString() === "Invalid Date")
2248
2795
  throw new RangeError("Member joined_at must be a valid date.");
2249
- this.permissions = new PermissionsBitField(data.permissions ?? 0n);
2796
+ if (data.permissions !== undefined)
2797
+ this.#suppliedPermissions = new PermissionsBitField(data.permissions);
2250
2798
  this.avatarHash = data.avatar ?? null;
2251
2799
  this.premiumSince = toDateOrNull(data.premium_since);
2252
2800
  this.timedOutUntil = toDateOrNull(data.communication_disabled_until);
2253
2801
  this.flags = data.flags ?? 0;
2254
2802
  }
2803
+ get permissions() {
2804
+ if (this.#suppliedPermissions)
2805
+ return this.#suppliedPermissions;
2806
+ return new PermissionsBitField(this.#context?.memberPermissions?.(this.guildId, this.user.id, this.roleIds) ?? 0n);
2807
+ }
2808
+ permissionsIn(channelId) {
2809
+ const computed = this.#context?.memberPermissions?.(this.guildId, this.user.id, this.roleIds, channelId);
2810
+ return computed ? new PermissionsBitField(computed) : null;
2811
+ }
2812
+ #action(name) {
2813
+ const action = this.#context?.[name];
2814
+ if (!action)
2815
+ throw new Error("This member is not attached to a client.");
2816
+ return action;
2817
+ }
2818
+ kick(reason) {
2819
+ return this.#action("kickMember")(this.guildId, this.user.id, reason);
2820
+ }
2821
+ ban(options = {}) {
2822
+ return this.#action("banMember")(this.guildId, this.user.id, options);
2823
+ }
2824
+ edit(options, reason) {
2825
+ return this.#action("editMember")(this.guildId, this.user.id, options, reason);
2826
+ }
2827
+ timeout(milliseconds, reason) {
2828
+ if (milliseconds !== null && !(milliseconds > 0))
2829
+ throw new RangeError("Timeout length must be a positive number of milliseconds.");
2830
+ return this.edit({
2831
+ communication_disabled_until: milliseconds === null ? null : new Date(Date.now() + milliseconds).toISOString()
2832
+ }, reason);
2833
+ }
2834
+ setNickname(nickname, reason) {
2835
+ return this.edit({ nick: nickname }, reason);
2836
+ }
2837
+ addRole(roleId, reason) {
2838
+ return this.#action("addMemberRole")(this.guildId, this.user.id, roleId, reason);
2839
+ }
2840
+ removeRole(roleId, reason) {
2841
+ return this.#action("removeMemberRole")(this.guildId, this.user.id, roleId, reason);
2842
+ }
2255
2843
  get displayName() {
2256
2844
  return this.nickname ?? this.user.displayName;
2257
2845
  }
@@ -2785,6 +3373,17 @@ class CommandOptions {
2785
3373
  throw new TypeError(`Resolved mentionable for option "${name}" is missing.`);
2786
3374
  return resolved;
2787
3375
  }
3376
+ getMentionableType(name) {
3377
+ const opt = this.#get(name);
3378
+ if (!opt || opt.type !== OptionType.Mentionable)
3379
+ return null;
3380
+ const id = String(opt.value);
3381
+ if (this.#resolved?.users?.[id])
3382
+ return "user";
3383
+ if (this.#resolved?.roles?.[id])
3384
+ return "role";
3385
+ return null;
3386
+ }
2788
3387
  getAttachment(name, required = false) {
2789
3388
  const opt = this.#get(name);
2790
3389
  if (!opt || opt.type !== OptionType.Attachment) {
@@ -2810,6 +3409,17 @@ var InteractionType = {
2810
3409
  ApplicationCommandAutocomplete: 4,
2811
3410
  ModalSubmit: 5
2812
3411
  };
3412
+ var EPHEMERAL = 64;
3413
+ var TOKEN_LIFETIME_MS = 15 * 60000;
3414
+ var DISCORD_EPOCH = 1420070400000n;
3415
+ function toMessageData(options) {
3416
+ if (typeof options === "string")
3417
+ return { content: options };
3418
+ const { ephemeral, ...data } = options;
3419
+ if (ephemeral)
3420
+ data.flags = (typeof data.flags === "number" ? data.flags : 0) | EPHEMERAL;
3421
+ return data;
3422
+ }
2813
3423
 
2814
3424
  class InteractionResponse {
2815
3425
  type;
@@ -2824,14 +3434,10 @@ class InteractionResponse {
2824
3434
  return this.data === undefined ? { type: this.type } : { type: this.type, data: this.data };
2825
3435
  }
2826
3436
  static message(options) {
2827
- const data = { ...options };
2828
- if (options.ephemeral) {
2829
- data.flags = (typeof options.flags === "number" ? options.flags : 0) | 64;
2830
- }
2831
- return new InteractionResponse(InteractionResponseType.ChannelMessage, data);
3437
+ return new InteractionResponse(InteractionResponseType.ChannelMessage, toMessageData(options));
2832
3438
  }
2833
3439
  static defer(ephemeral = false) {
2834
- return new InteractionResponse(InteractionResponseType.DeferredChannelMessage, ephemeral ? { flags: 64 } : undefined);
3440
+ return new InteractionResponse(InteractionResponseType.DeferredChannelMessage, ephemeral ? { flags: EPHEMERAL } : undefined);
2835
3441
  }
2836
3442
  static pong() {
2837
3443
  return new InteractionResponse(InteractionResponseType.Pong);
@@ -2849,6 +3455,7 @@ class Interaction {
2849
3455
  replied = false;
2850
3456
  deferred = false;
2851
3457
  #client;
3458
+ #acknowledging = false;
2852
3459
  constructor(client, data) {
2853
3460
  if (!data.id || !data.token)
2854
3461
  throw new TypeError("Interaction ID and token are required.");
@@ -2864,6 +3471,20 @@ class Interaction {
2864
3471
  isChatInputCommand() {
2865
3472
  return this.type === InteractionType.ApplicationCommand;
2866
3473
  }
3474
+ awaitModalSubmit(options) {
3475
+ const collect = this.#client.resourceContext?.collectInteractions;
3476
+ if (!collect)
3477
+ return Promise.reject(new Error("This interaction is not attached to a client."));
3478
+ if (!(options.time > 0))
3479
+ return Promise.reject(new RangeError("awaitModalSubmit needs a positive time."));
3480
+ const userId = this.user?.id;
3481
+ const collector = collect({
3482
+ time: options.time,
3483
+ max: 1,
3484
+ filter: async (interaction) => interaction.isModalSubmit() && interaction.user?.id === userId && (options.customId === undefined || interaction.customId === options.customId) && (options.filter ? await options.filter(interaction) : true)
3485
+ });
3486
+ return collector.next();
3487
+ }
2867
3488
  isMessageComponent() {
2868
3489
  return this.type === InteractionType.MessageComponent;
2869
3490
  }
@@ -2898,9 +3519,57 @@ class Interaction {
2898
3519
  return [3, 5, 6, 7, 8].includes(this.#componentType());
2899
3520
  }
2900
3521
  assertUnacknowledged() {
2901
- if (this.replied || this.deferred)
3522
+ if (this.replied || this.deferred || this.#acknowledging)
2902
3523
  throw new Error("Interaction has already been acknowledged.");
2903
3524
  }
3525
+ async acknowledge(response, state) {
3526
+ this.assertUnacknowledged();
3527
+ this.#acknowledging = true;
3528
+ try {
3529
+ const result = await this.postResponse(response);
3530
+ this[state] = true;
3531
+ return result;
3532
+ } finally {
3533
+ this.#acknowledging = false;
3534
+ }
3535
+ }
3536
+ get user() {
3537
+ const raw = this.data.member?.user ?? this.data.user;
3538
+ return raw ? new User(raw) : null;
3539
+ }
3540
+ get member() {
3541
+ const raw = this.data.member;
3542
+ if (!raw || !this.guildId)
3543
+ return null;
3544
+ return new GuildMember({
3545
+ ...raw,
3546
+ guild_id: this.guildId
3547
+ }, this.#client.resourceContext);
3548
+ }
3549
+ get createdTimestamp() {
3550
+ return Number((BigInt(this.id) >> 22n) + DISCORD_EPOCH);
3551
+ }
3552
+ get expiresAt() {
3553
+ return new Date(this.createdTimestamp + TOKEN_LIFETIME_MS);
3554
+ }
3555
+ get isExpired() {
3556
+ return Date.now() >= this.createdTimestamp + TOKEN_LIFETIME_MS;
3557
+ }
3558
+ #webhookMessage(method, messageId, data) {
3559
+ if (!this.#client.interactionWebhookMessage)
3560
+ return Promise.reject(new Error("This interaction client does not support webhook message access."));
3561
+ return this.#client.interactionWebhookMessage(method, this.applicationId, this.token, messageId, data);
3562
+ }
3563
+ fetchReply() {
3564
+ this.assertAcknowledged();
3565
+ return this.#webhookMessage("GET", "@original");
3566
+ }
3567
+ editFollowUp(messageId, options) {
3568
+ return this.#webhookMessage("PATCH", messageId, toMessageData(options));
3569
+ }
3570
+ async deleteFollowUp(messageId) {
3571
+ await this.#webhookMessage("DELETE", messageId);
3572
+ }
2904
3573
  assertAcknowledged() {
2905
3574
  if (!this.replied && !this.deferred)
2906
3575
  throw new Error("Interaction has not been acknowledged.");
@@ -2909,41 +3578,29 @@ class Interaction {
2909
3578
  return this.#client.postInteractionResponse(this.id, this.token, response);
2910
3579
  }
2911
3580
  async reply(options) {
2912
- this.assertUnacknowledged();
2913
- const payload = typeof options === "string" ? { content: options } : options;
2914
- const result = await this.#client.postInteractionResponse(this.id, this.token, InteractionResponse.message(payload));
2915
- this.replied = true;
2916
- return result;
3581
+ return this.acknowledge(InteractionResponse.message(toMessageData(options)), "replied");
2917
3582
  }
2918
- async deferReply(ephemeral = false) {
2919
- this.assertUnacknowledged();
2920
- await this.#client.postInteractionResponse(this.id, this.token, InteractionResponse.defer(ephemeral));
2921
- this.deferred = true;
3583
+ async deferReply(options = false) {
3584
+ const ephemeral = typeof options === "boolean" ? options : options.ephemeral === true;
3585
+ await this.acknowledge(InteractionResponse.defer(ephemeral), "deferred");
2922
3586
  }
2923
3587
  editReply(options) {
2924
3588
  this.assertAcknowledged();
2925
- return this.#client.editInteractionReply(this.token, options);
3589
+ return this.#client.editInteractionReply(this.token, toMessageData(options));
2926
3590
  }
2927
3591
  deleteReply() {
2928
3592
  this.assertAcknowledged();
2929
3593
  return this.#client.deleteInteractionReply(this.token);
2930
3594
  }
2931
3595
  followUp(options) {
2932
- const payload = typeof options === "string" ? { content: options } : options;
2933
- return this.#client.followUpInteraction(this.token, payload);
3596
+ return this.#client.followUpInteraction(this.token, toMessageData(options));
2934
3597
  }
2935
3598
  async update(options) {
2936
- this.assertUnacknowledged();
2937
- const payload = typeof options === "string" ? { content: options } : options;
2938
- const result = await this.#client.postInteractionResponse(this.id, this.token, new InteractionResponse(InteractionResponseType.MessageUpdate, payload));
2939
- this.replied = true;
2940
- return result;
3599
+ return this.acknowledge(new InteractionResponse(InteractionResponseType.MessageUpdate, toMessageData(options)), "replied");
2941
3600
  }
2942
3601
  async showModal(modal) {
2943
- this.assertUnacknowledged();
2944
- const result = await this.#client.postInteractionResponse(this.id, this.token, new InteractionResponse(InteractionResponseType.Modal, modal));
2945
- this.replied = true;
2946
- return result;
3602
+ const data = "toJSON" in modal && typeof modal.toJSON === "function" ? modal.toJSON() : modal;
3603
+ return this.acknowledge(new InteractionResponse(InteractionResponseType.Modal, data), "replied");
2947
3604
  }
2948
3605
  }
2949
3606
 
@@ -2964,6 +3621,9 @@ class ComponentInteraction extends Interaction {
2964
3621
  get customId() {
2965
3622
  return this.data?.data?.custom_id ?? "";
2966
3623
  }
3624
+ get messageId() {
3625
+ return this.data?.message?.id;
3626
+ }
2967
3627
  get componentType() {
2968
3628
  return this.data?.data?.component_type ?? 0;
2969
3629
  }
@@ -2971,16 +3631,10 @@ class ComponentInteraction extends Interaction {
2971
3631
  return this.data?.data?.values ?? [];
2972
3632
  }
2973
3633
  async deferUpdate() {
2974
- this.assertUnacknowledged();
2975
- await this.postResponse(new InteractionResponse(InteractionResponseType.DeferredMessageUpdate));
2976
- this.deferred = true;
3634
+ await this.acknowledge(new InteractionResponse(InteractionResponseType.DeferredMessageUpdate), "deferred");
2977
3635
  }
2978
3636
  async update(options) {
2979
- this.assertUnacknowledged();
2980
- const payload = typeof options === "string" ? { content: options } : options;
2981
- const result = await this.postResponse(new InteractionResponse(InteractionResponseType.MessageUpdate, payload));
2982
- this.replied = true;
2983
- return result;
3637
+ return this.acknowledge(new InteractionResponse(InteractionResponseType.MessageUpdate, toMessageData(options)), "replied");
2984
3638
  }
2985
3639
  }
2986
3640
 
@@ -3023,8 +3677,7 @@ class AutocompleteInteraction extends Interaction {
3023
3677
  if (!Array.isArray(choices))
3024
3678
  throw new TypeError("Autocomplete choices must be an array.");
3025
3679
  const response = new InteractionResponse(InteractionResponseType.Autocomplete, { choices });
3026
- await this.postResponse(response);
3027
- this.replied = true;
3680
+ await this.acknowledge(response, "replied");
3028
3681
  }
3029
3682
  }
3030
3683
  function findFocused(options) {
@@ -3221,6 +3874,7 @@ class AuditLog {
3221
3874
  }
3222
3875
 
3223
3876
  // packages/structures/src/index.ts
3877
+ var COMPONENT_COLLECTOR_DEFAULT_TIME = 15 * 60000;
3224
3878
  var NON_SYSTEM_MESSAGE_TYPES = new Set([0, 19, 20, 23]);
3225
3879
 
3226
3880
  class Message extends BaseStructure {
@@ -3241,6 +3895,7 @@ class Message extends BaseStructure {
3241
3895
  reference;
3242
3896
  components;
3243
3897
  referencedMessage;
3898
+ member;
3244
3899
  #context;
3245
3900
  constructor(data, context) {
3246
3901
  super(data.id);
@@ -3263,6 +3918,11 @@ class Message extends BaseStructure {
3263
3918
  this.reference = data.message_reference;
3264
3919
  this.referencedMessage = data.referenced_message ? new Message(data.referenced_message, context) : data.referenced_message === null ? null : undefined;
3265
3920
  this.#context = context;
3921
+ this.member = data.member && data.guild_id ? new GuildMember({
3922
+ ...data.member,
3923
+ user: data.member.user ?? data.author,
3924
+ guild_id: data.guild_id
3925
+ }, context) : null;
3266
3926
  this.channel = new Channel({ id: data.channel_id, type: 0, guild_id: data.guild_id }, context);
3267
3927
  }
3268
3928
  get embedsSuppressed() {
@@ -3303,6 +3963,20 @@ class Message extends BaseStructure {
3303
3963
  throw new Error("This message is not attached to a client.");
3304
3964
  return this.#context.crosspostMessage(this.channelId, this.id);
3305
3965
  }
3966
+ createComponentCollector(options = {}) {
3967
+ const collect = this.#context?.collectInteractions;
3968
+ if (!collect)
3969
+ throw new Error("This message is not attached to a client.");
3970
+ const { componentType, filter, ...rest } = options;
3971
+ return collect({
3972
+ ...rest,
3973
+ time: rest.time ?? (rest.idle ? undefined : COMPONENT_COLLECTOR_DEFAULT_TIME),
3974
+ filter: async (interaction) => interaction.isMessageComponent() && interaction.messageId === this.id && (componentType === undefined || interaction.componentType === componentType) && (filter ? await filter(interaction) : true)
3975
+ });
3976
+ }
3977
+ awaitComponent(options = {}) {
3978
+ return this.createComponentCollector({ ...options, max: 1 }).next();
3979
+ }
3306
3980
  react(emoji) {
3307
3981
  if (!this.#context?.addReaction)
3308
3982
  throw new Error("This message is not attached to a client.");
@@ -3376,23 +4050,43 @@ class Message extends BaseStructure {
3376
4050
  }
3377
4051
 
3378
4052
  // packages/managers/src/message.ts
4053
+ function toRequest(options) {
4054
+ const { files, ...body } = options;
4055
+ if (!files?.length)
4056
+ return body;
4057
+ return {
4058
+ body,
4059
+ files: files.map((file) => ({
4060
+ name: file.name,
4061
+ data: typeof file.data === "string" ? new TextEncoder().encode(file.data) : file.data,
4062
+ contentType: file.contentType
4063
+ }))
4064
+ };
4065
+ }
4066
+
3379
4067
  class MessageManager {
3380
- cache = new Collection;
4068
+ cache;
4069
+ #caching;
3381
4070
  #rest;
3382
4071
  #context;
3383
4072
  #channelId;
3384
- constructor(rest, context, channelId) {
4073
+ constructor(rest, context, channelId, cache) {
3385
4074
  if (!channelId)
3386
4075
  throw new TypeError("Channel ID is required.");
3387
4076
  this.#rest = rest;
3388
4077
  this.#context = context;
3389
4078
  this.#channelId = channelId;
4079
+ this.#caching = cache !== undefined;
4080
+ this.cache = new Collection(null, {
4081
+ ttl: cache?.ttl,
4082
+ maxSize: cache ? cache.maxSize ?? 100 : undefined
4083
+ });
3390
4084
  }
3391
4085
  async resolve(messageId) {
3392
4086
  return this.cache.get(messageId) ?? this.fetch(messageId);
3393
4087
  }
3394
4088
  async send(options) {
3395
- const data = await this.#rest.post(Routes.channelMessages(this.#channelId), options);
4089
+ const data = await this.#rest.post(Routes.channelMessages(this.#channelId), toRequest(options));
3396
4090
  return this.upsert(data);
3397
4091
  }
3398
4092
  async fetch(messageId) {
@@ -3403,13 +4097,14 @@ class MessageManager {
3403
4097
  return Promise.all(Array.from(messageIds, (messageId) => this.fetch(messageId)));
3404
4098
  }
3405
4099
  upsert(data) {
3406
- const existing = this.cache.get(data.id);
4100
+ const existing = this.cache.peek(data.id);
3407
4101
  const message = new Message(data, this.#context);
3408
4102
  if (existing) {
3409
4103
  Object.assign(existing, message);
3410
4104
  return existing;
3411
4105
  }
3412
- this.cache.set(message.id, message);
4106
+ if (this.#caching)
4107
+ this.cache.set(message.id, message);
3413
4108
  return message;
3414
4109
  }
3415
4110
  delete(messageId) {
@@ -3463,17 +4158,58 @@ class UserManager extends ResourceManager {
3463
4158
  });
3464
4159
  }
3465
4160
  }
3466
- // packages/managers/src/guild-resources.ts
3467
- function withQuery(path, params) {
3468
- const query = new URLSearchParams;
3469
- for (const [key, value] of Object.entries(params))
4161
+ // packages/managers/src/emoji.ts
4162
+ class EmojiManager extends Manager {
4163
+ #rest;
4164
+ #guildId;
4165
+ constructor(rest, guildId) {
4166
+ super();
4167
+ this.#rest = rest;
4168
+ this.#guildId = guildId;
4169
+ }
4170
+ fetch(emojiId) {
4171
+ return this.fetchOnce(emojiId, async () => new Emoji(await this.#rest.get(Routes.guildEmoji(this.#guildId, emojiId))), (emoji) => this.#merge(emojiId, emoji));
4172
+ }
4173
+ async fetchAll() {
4174
+ const data = await this.#rest.get(Routes.guildEmoji(this.#guildId));
4175
+ return data.map((item) => this.upsert(item));
4176
+ }
4177
+ async create(options) {
4178
+ return this.upsert(await this.#rest.post(Routes.guildEmoji(this.#guildId), options));
4179
+ }
4180
+ async edit(emojiId, options) {
4181
+ return this.upsert(await this.#rest.patch(Routes.guildEmoji(this.#guildId, emojiId), options));
4182
+ }
4183
+ async deleteEmoji(emojiId) {
4184
+ await this.#rest.delete(Routes.guildEmoji(this.#guildId, emojiId));
4185
+ this.delete(emojiId);
4186
+ }
4187
+ upsert(data) {
4188
+ const key = data.id != null ? data.id : `unicode:${data.name ?? ""}`;
4189
+ return this.#merge(key, new Emoji(data));
4190
+ }
4191
+ #merge(key, emoji) {
4192
+ const existing = this.get(key);
4193
+ if (existing) {
4194
+ Object.assign(existing, emoji);
4195
+ return existing;
4196
+ }
4197
+ this.set(key, emoji);
4198
+ return emoji;
4199
+ }
4200
+ }
4201
+
4202
+ // packages/managers/src/advanced.ts
4203
+ function withQuery(path, query) {
4204
+ const params = new URLSearchParams;
4205
+ for (const [key, value] of Object.entries(query))
3470
4206
  if (value !== undefined)
3471
- query.set(key, String(value));
3472
- const suffix = query.toString();
4207
+ params.set(key, String(value));
4208
+ const suffix = params.toString();
3473
4209
  return suffix ? `${path}?${suffix}` : path;
3474
4210
  }
3475
4211
 
3476
- class GuildBanManager extends Manager {
4212
+ class GuildStickerManager extends Manager {
3477
4213
  #rest;
3478
4214
  guildId;
3479
4215
  constructor(rest, guildId) {
@@ -3481,21 +4217,273 @@ class GuildBanManager extends Manager {
3481
4217
  this.#rest = rest;
3482
4218
  this.guildId = guildId;
3483
4219
  }
3484
- async fetch(userId) {
3485
- const ban = await this.#rest.get(Routes.guildBan(this.guildId, userId));
3486
- this.set(ban.user.id, ban);
3487
- return ban;
4220
+ #store(sticker) {
4221
+ this.set(sticker.id, sticker);
4222
+ return sticker;
3488
4223
  }
3489
- async fetchAll(options = {}) {
3490
- const limit = options.limit === undefined ? undefined : Math.min(1000, Math.max(1, options.limit));
3491
- const bans = await this.#rest.get(withQuery(Routes.guildBans(this.guildId), {
3492
- limit,
3493
- before: options.before,
3494
- after: options.after
3495
- }));
3496
- for (const ban of bans)
3497
- this.set(ban.user.id, ban);
3498
- return bans;
4224
+ async fetchAll() {
4225
+ const stickers = await this.#rest.get(Routes.guildSticker(this.guildId));
4226
+ this.clear();
4227
+ return stickers.map((sticker) => this.#store(sticker));
4228
+ }
4229
+ async fetch(stickerId) {
4230
+ return this.#store(await this.#rest.get(Routes.guildSticker(this.guildId, stickerId)));
4231
+ }
4232
+ async create(options) {
4233
+ const form = new FormData;
4234
+ form.set("name", options.name);
4235
+ form.set("description", options.description);
4236
+ form.set("tags", options.tags);
4237
+ form.set("file", options.file);
4238
+ return this.#store(await this.#rest.post(Routes.guildSticker(this.guildId), form, { reason: options.reason }));
4239
+ }
4240
+ async edit(stickerId, options) {
4241
+ const { reason, ...body } = options;
4242
+ return this.#store(await this.#rest.patch(Routes.guildSticker(this.guildId, stickerId), body, { reason }));
4243
+ }
4244
+ async remove(stickerId, reason) {
4245
+ await this.#rest.delete(Routes.guildSticker(this.guildId, stickerId), {
4246
+ reason
4247
+ });
4248
+ this.delete(stickerId);
4249
+ }
4250
+ sync(stickers) {
4251
+ this.clear();
4252
+ for (const sticker of stickers)
4253
+ this.#store(sticker);
4254
+ }
4255
+ }
4256
+
4257
+ class GuildSoundboardManager extends Manager {
4258
+ #rest;
4259
+ guildId;
4260
+ constructor(rest, guildId) {
4261
+ super();
4262
+ this.#rest = rest;
4263
+ this.guildId = guildId;
4264
+ }
4265
+ #store(sound) {
4266
+ this.set(sound.sound_id, sound);
4267
+ return sound;
4268
+ }
4269
+ async fetchAll() {
4270
+ const { items } = await this.#rest.get(Routes.guildSoundboardSound(this.guildId));
4271
+ this.clear();
4272
+ return items.map((sound) => this.#store(sound));
4273
+ }
4274
+ async fetch(soundId) {
4275
+ return this.#store(await this.#rest.get(Routes.guildSoundboardSound(this.guildId, soundId)));
4276
+ }
4277
+ async create(options) {
4278
+ if (options.volume !== undefined && (options.volume < 0 || options.volume > 1))
4279
+ throw new RangeError("Soundboard volume must be between 0 and 1.");
4280
+ return this.#store(await this.#rest.post(Routes.guildSoundboardSound(this.guildId), {
4281
+ name: options.name,
4282
+ sound: options.sound,
4283
+ volume: options.volume,
4284
+ emoji_id: options.emojiId,
4285
+ emoji_name: options.emojiName
4286
+ }, { reason: options.reason }));
4287
+ }
4288
+ async edit(soundId, options) {
4289
+ return this.#store(await this.#rest.patch(Routes.guildSoundboardSound(this.guildId, soundId), {
4290
+ name: options.name,
4291
+ volume: options.volume,
4292
+ emoji_id: options.emojiId,
4293
+ emoji_name: options.emojiName
4294
+ }, { reason: options.reason }));
4295
+ }
4296
+ async remove(soundId, reason) {
4297
+ await this.#rest.delete(Routes.guildSoundboardSound(this.guildId, soundId), { reason });
4298
+ this.delete(soundId);
4299
+ }
4300
+ }
4301
+
4302
+ class MonetizationManager extends Manager {
4303
+ #rest;
4304
+ applicationId;
4305
+ constructor(rest, applicationId) {
4306
+ super();
4307
+ this.#rest = rest;
4308
+ this.applicationId = applicationId;
4309
+ }
4310
+ fetchSkus() {
4311
+ return this.#rest.get(Routes.applicationSkus(this.applicationId));
4312
+ }
4313
+ async fetchEntitlements(query = {}) {
4314
+ if (query.limit !== undefined && (!Number.isInteger(query.limit) || query.limit < 1 || query.limit > 100))
4315
+ throw new RangeError("Entitlement limit must be 1-100.");
4316
+ const entitlements = await this.#rest.get(withQuery(Routes.applicationEntitlement(this.applicationId), {
4317
+ user_id: query.userId,
4318
+ sku_ids: query.skuIds?.join(","),
4319
+ guild_id: query.guildId,
4320
+ before: query.before,
4321
+ after: query.after,
4322
+ limit: query.limit,
4323
+ exclude_ended: query.excludeEnded,
4324
+ exclude_deleted: query.excludeDeleted
4325
+ }));
4326
+ for (const entitlement of entitlements)
4327
+ this.set(entitlement.id, entitlement);
4328
+ return entitlements;
4329
+ }
4330
+ async fetch(entitlementId) {
4331
+ const entitlement = await this.#rest.get(Routes.applicationEntitlement(this.applicationId, entitlementId));
4332
+ this.set(entitlement.id, entitlement);
4333
+ return entitlement;
4334
+ }
4335
+ async consume(entitlementId) {
4336
+ await this.#rest.post(Routes.consumeEntitlement(this.applicationId, entitlementId));
4337
+ const cached = this.get(entitlementId);
4338
+ if (cached)
4339
+ cached.consumed = true;
4340
+ }
4341
+ async createTestEntitlement(options) {
4342
+ const entitlement = await this.#rest.post(Routes.applicationEntitlement(this.applicationId), {
4343
+ sku_id: options.skuId,
4344
+ owner_id: options.ownerId,
4345
+ owner_type: options.ownerType
4346
+ });
4347
+ this.set(entitlement.id, entitlement);
4348
+ return entitlement;
4349
+ }
4350
+ async deleteTestEntitlement(entitlementId) {
4351
+ await this.#rest.delete(Routes.applicationEntitlement(this.applicationId, entitlementId));
4352
+ this.delete(entitlementId);
4353
+ }
4354
+ fetchSubscriptions(skuId, query = {}) {
4355
+ return this.#rest.get(withQuery(Routes.skuSubscription(skuId), {
4356
+ user_id: query.userId,
4357
+ before: query.before,
4358
+ after: query.after,
4359
+ limit: query.limit
4360
+ }));
4361
+ }
4362
+ fetchSubscription(skuId, subscriptionId) {
4363
+ return this.#rest.get(Routes.skuSubscription(skuId, subscriptionId));
4364
+ }
4365
+ }
4366
+
4367
+ // packages/managers/src/member.ts
4368
+ class GuildMemberManager extends ResourceManager {
4369
+ #rest;
4370
+ #context;
4371
+ guildId;
4372
+ constructor(guildId, rest, context = () => {
4373
+ return;
4374
+ }) {
4375
+ super((id) => rest.get(Routes.guildMember(guildId, id)).then((data) => new GuildMember({ ...data, guild_id: guildId }, context())), (member) => member.user.id);
4376
+ this.guildId = guildId;
4377
+ this.#rest = rest;
4378
+ this.#context = context;
4379
+ }
4380
+ async kick(userId, reason) {
4381
+ await this.#rest.delete(Routes.guildMember(this.guildId, userId), {
4382
+ reason
4383
+ });
4384
+ this.delete(userId);
4385
+ }
4386
+ async ban(userId, options = {}) {
4387
+ await this.#rest.put(Routes.guildBan(this.guildId, userId), { delete_message_seconds: options.deleteMessageSeconds }, { reason: options.reason });
4388
+ this.delete(userId);
4389
+ }
4390
+ async unban(userId) {
4391
+ await this.#rest.delete(Routes.guildBan(this.guildId, userId));
4392
+ }
4393
+ async edit(userId, options, reason) {
4394
+ const data = await this.#rest.patch(Routes.guildMember(this.guildId, userId), options, { reason });
4395
+ const member = new GuildMember({ ...data, guild_id: this.guildId }, this.#context());
4396
+ this.set(member.user.id, member);
4397
+ return member;
4398
+ }
4399
+ async addRole(userId, roleId, reason) {
4400
+ await this.#rest.put(Routes.guildMemberRole(this.guildId, userId, roleId), undefined, { reason });
4401
+ }
4402
+ async removeRole(userId, roleId, reason) {
4403
+ await this.#rest.delete(Routes.guildMemberRole(this.guildId, userId, roleId), { reason });
4404
+ }
4405
+ async timeout(userId, milliseconds, reason) {
4406
+ const timeoutDate = milliseconds === null ? null : new Date(Date.now() + milliseconds).toISOString();
4407
+ return this.edit(userId, { communication_disabled_until: timeoutDate }, reason);
4408
+ }
4409
+ }
4410
+
4411
+ // packages/managers/src/role.ts
4412
+ class RoleManager extends ResourceManager {
4413
+ #rest;
4414
+ guildId;
4415
+ constructor(guildId, rest) {
4416
+ super((id) => rest.get(Routes.guildRole(guildId, id)).then((data) => new Role(data)), (role) => role.id);
4417
+ this.guildId = guildId;
4418
+ this.#rest = rest;
4419
+ }
4420
+ async fetchAll() {
4421
+ const data = await this.#rest.get(Routes.guildRoles(this.guildId));
4422
+ return data.map((item) => {
4423
+ const role = new Role(item);
4424
+ this.set(role.id, role);
4425
+ return role;
4426
+ });
4427
+ }
4428
+ async create(options) {
4429
+ const { reason, ...payload } = options;
4430
+ const data = await this.#rest.post(Routes.guildRoles(this.guildId), {
4431
+ ...payload,
4432
+ permissions: payload.permissions !== undefined ? String(payload.permissions) : undefined
4433
+ });
4434
+ const role = new Role(data);
4435
+ this.set(role.id, role);
4436
+ return role;
4437
+ }
4438
+ async edit(roleId, options) {
4439
+ const { reason, ...payload } = options;
4440
+ const data = await this.#rest.patch(Routes.guildRole(this.guildId, roleId), {
4441
+ ...payload,
4442
+ permissions: payload.permissions !== undefined ? String(payload.permissions) : undefined
4443
+ });
4444
+ const role = new Role(data);
4445
+ this.set(role.id, role);
4446
+ return role;
4447
+ }
4448
+ async deleteRole(roleId) {
4449
+ await this.#rest.delete(Routes.guildRole(this.guildId, roleId));
4450
+ this.delete(roleId);
4451
+ }
4452
+ }
4453
+
4454
+ // packages/managers/src/guild-resources.ts
4455
+ function withQuery2(path, params) {
4456
+ const query = new URLSearchParams;
4457
+ for (const [key, value] of Object.entries(params))
4458
+ if (value !== undefined)
4459
+ query.set(key, String(value));
4460
+ const suffix = query.toString();
4461
+ return suffix ? `${path}?${suffix}` : path;
4462
+ }
4463
+
4464
+ class GuildBanManager extends Manager {
4465
+ #rest;
4466
+ guildId;
4467
+ constructor(rest, guildId) {
4468
+ super();
4469
+ this.#rest = rest;
4470
+ this.guildId = guildId;
4471
+ }
4472
+ async fetch(userId) {
4473
+ const ban = await this.#rest.get(Routes.guildBan(this.guildId, userId));
4474
+ this.set(ban.user.id, ban);
4475
+ return ban;
4476
+ }
4477
+ async fetchAll(options = {}) {
4478
+ const limit = options.limit === undefined ? undefined : Math.min(1000, Math.max(1, options.limit));
4479
+ const bans = await this.#rest.get(withQuery2(Routes.guildBans(this.guildId), {
4480
+ limit,
4481
+ before: options.before,
4482
+ after: options.after
4483
+ }));
4484
+ for (const ban of bans)
4485
+ this.set(ban.user.id, ban);
4486
+ return bans;
3499
4487
  }
3500
4488
  async create(userId, options = {}) {
3501
4489
  await this.#rest.put(Routes.guildBan(this.guildId, userId), { delete_message_seconds: options.deleteMessageSeconds }, { reason: options.reason });
@@ -3521,12 +4509,12 @@ class GuildScheduledEventManager extends Manager {
3521
4509
  return event;
3522
4510
  }
3523
4511
  async fetch(eventId, options = {}) {
3524
- return this.#store(await this.#rest.get(withQuery(Routes.guildScheduledEvent(this.guildId, eventId), {
4512
+ return this.#store(await this.#rest.get(withQuery2(Routes.guildScheduledEvent(this.guildId, eventId), {
3525
4513
  with_user_count: options.withUserCount
3526
4514
  })));
3527
4515
  }
3528
4516
  async fetchAll(options = {}) {
3529
- const events = await this.#rest.get(withQuery(Routes.guildScheduledEvents(this.guildId), {
4517
+ const events = await this.#rest.get(withQuery2(Routes.guildScheduledEvents(this.guildId), {
3530
4518
  with_user_count: options.withUserCount
3531
4519
  }));
3532
4520
  return events.map((event) => this.#store(event));
@@ -3543,7 +4531,7 @@ class GuildScheduledEventManager extends Manager {
3543
4531
  }
3544
4532
  async fetchSubscribers(eventId, options = {}) {
3545
4533
  const limit = options.limit === undefined ? undefined : Math.min(100, Math.max(1, options.limit));
3546
- return this.#rest.get(withQuery(Routes.guildScheduledEventUsers(this.guildId, eventId), {
4534
+ return this.#rest.get(withQuery2(Routes.guildScheduledEventUsers(this.guildId, eventId), {
3547
4535
  limit,
3548
4536
  with_member: options.withMember,
3549
4537
  before: options.before,
@@ -3587,10 +4575,25 @@ class StageInstanceManager extends Manager {
3587
4575
 
3588
4576
  class PermissionOverwriteManager {
3589
4577
  #rest;
4578
+ #current;
3590
4579
  channelId;
3591
- constructor(rest, channelId) {
4580
+ constructor(rest, channelId, current = () => {
4581
+ return;
4582
+ }) {
3592
4583
  this.#rest = rest;
3593
4584
  this.channelId = channelId;
4585
+ this.#current = current;
4586
+ }
4587
+ async update(overwriteId, changes, options = {}) {
4588
+ const overwrites = this.#current() ?? (await this.#rest.get(Routes.channel(this.channelId))).permission_overwrites ?? [];
4589
+ const existing = overwrites.find((entry) => entry.id === overwriteId);
4590
+ const type = existing?.type ?? options.type;
4591
+ if (type !== 0 && type !== 1)
4592
+ throw new TypeError("A new permission overwrite needs a type: 0 for a role, 1 for a member.");
4593
+ const touched = (changes.allow ?? 0n) | (changes.deny ?? 0n) | (changes.inherit ?? 0n);
4594
+ const allow = BigInt(existing?.allow ?? 0) & ~touched | (changes.allow ?? 0n);
4595
+ const deny = BigInt(existing?.deny ?? 0) & ~touched | (changes.deny ?? 0n);
4596
+ await this.edit(overwriteId, { type, allow, deny }, options.reason);
3594
4597
  }
3595
4598
  async edit(overwriteId, options, reason) {
3596
4599
  await this.#rest.put(Routes.channelPermission(this.channelId, overwriteId), {
@@ -3605,7 +4608,7 @@ class PermissionOverwriteManager {
3605
4608
  }
3606
4609
 
3607
4610
  // packages/managers/src/guild.ts
3608
- function withQuery2(path, params) {
4611
+ function withQuery3(path, params) {
3609
4612
  const suffix = params.toString();
3610
4613
  return suffix ? `${path}?${suffix}` : path;
3611
4614
  }
@@ -3614,6 +4617,24 @@ class GuildManager extends ResourceManager {
3614
4617
  #rest;
3615
4618
  #bans = new Map;
3616
4619
  #scheduledEvents = new Map;
4620
+ #members = new Map;
4621
+ #roles = new Map;
4622
+ #emojis = new Map;
4623
+ #stickers = new Map;
4624
+ #soundboard = new Map;
4625
+ #voiceStates = new Map;
4626
+ #autoModerationRules = new Map;
4627
+ #invites = new Map;
4628
+ #context;
4629
+ attachContext(context) {
4630
+ this.#context = context;
4631
+ }
4632
+ #perGuild(map, guildId, create) {
4633
+ let manager = map.get(guildId);
4634
+ if (!manager)
4635
+ map.set(guildId, manager = create());
4636
+ return manager;
4637
+ }
3617
4638
  constructor(rest) {
3618
4639
  super(async (id) => new Guild(await rest.get(Routes.guild(id))), (guild) => guild.id);
3619
4640
  this.#rest = rest;
@@ -3630,6 +4651,68 @@ class GuildManager extends ResourceManager {
3630
4651
  this.#scheduledEvents.set(guildId, manager = new GuildScheduledEventManager(this.#rest, guildId));
3631
4652
  return manager;
3632
4653
  }
4654
+ members(guildId) {
4655
+ let manager = this.#members.get(guildId);
4656
+ if (!manager)
4657
+ this.#members.set(guildId, manager = new GuildMemberManager(guildId, this.#rest, () => this.#context));
4658
+ return manager;
4659
+ }
4660
+ roles(guildId) {
4661
+ let manager = this.#roles.get(guildId);
4662
+ if (!manager)
4663
+ this.#roles.set(guildId, manager = new RoleManager(guildId, this.#rest));
4664
+ return manager;
4665
+ }
4666
+ emojis(guildId) {
4667
+ let manager = this.#emojis.get(guildId);
4668
+ if (!manager)
4669
+ this.#emojis.set(guildId, manager = new EmojiManager(this.#rest, guildId));
4670
+ return manager;
4671
+ }
4672
+ stickers(guildId) {
4673
+ let manager = this.#stickers.get(guildId);
4674
+ if (!manager)
4675
+ this.#stickers.set(guildId, manager = new GuildStickerManager(this.#rest, guildId));
4676
+ return manager;
4677
+ }
4678
+ soundboard(guildId) {
4679
+ let manager = this.#soundboard.get(guildId);
4680
+ if (!manager)
4681
+ this.#soundboard.set(guildId, manager = new GuildSoundboardManager(this.#rest, guildId));
4682
+ return manager;
4683
+ }
4684
+ voiceStates(guildId) {
4685
+ return this.#perGuild(this.#voiceStates, guildId, () => new Manager);
4686
+ }
4687
+ autoModerationRules(guildId) {
4688
+ return this.#perGuild(this.#autoModerationRules, guildId, () => new Manager);
4689
+ }
4690
+ invites(guildId) {
4691
+ return this.#perGuild(this.#invites, guildId, () => new Manager);
4692
+ }
4693
+ patch(data) {
4694
+ const guild = new Guild(data);
4695
+ const existing = this.get(guild.id);
4696
+ if (!existing)
4697
+ return this.upsert(guild);
4698
+ for (const [key, value] of Object.entries(guild))
4699
+ if (value !== undefined)
4700
+ existing[key] = value;
4701
+ return existing;
4702
+ }
4703
+ delete(id) {
4704
+ this.#bans.delete(id);
4705
+ this.#scheduledEvents.delete(id);
4706
+ this.#members.delete(id);
4707
+ this.#roles.delete(id);
4708
+ this.#emojis.delete(id);
4709
+ this.#stickers.delete(id);
4710
+ this.#soundboard.delete(id);
4711
+ this.#voiceStates.delete(id);
4712
+ this.#autoModerationRules.delete(id);
4713
+ this.#invites.delete(id);
4714
+ return super.delete(id);
4715
+ }
3633
4716
  async create(options) {
3634
4717
  const data = await this.#rest.post("/guilds", options);
3635
4718
  return this.upsert(new Guild(data));
@@ -3665,7 +4748,7 @@ class GuildManager extends ResourceManager {
3665
4748
  params.set("after", options.after);
3666
4749
  if (options.limit !== undefined)
3667
4750
  params.set("limit", String(Math.min(100, Math.max(1, options.limit))));
3668
- return this.#rest.get(withQuery2(Routes.guildAuditLog(guildId), params));
4751
+ return this.#rest.get(withQuery3(Routes.guildAuditLog(guildId), params));
3669
4752
  }
3670
4753
  async fetchMembers(guildId, options = {}) {
3671
4754
  const params = new URLSearchParams;
@@ -3673,160 +4756,81 @@ class GuildManager extends ResourceManager {
3673
4756
  params.set("limit", String(Math.min(1000, Math.max(1, options.limit))));
3674
4757
  if (options.after)
3675
4758
  params.set("after", options.after);
3676
- return this.#rest.get(withQuery2(Routes.guildMembers(guildId), params));
4759
+ return this.#rest.get(withQuery3(Routes.guildMembers(guildId), params));
3677
4760
  }
3678
4761
  async fetchAutoModerationRules(guildId) {
3679
4762
  const rules = await this.#rest.get(Routes.guildAutoModerationRules(guildId));
3680
4763
  return rules.map((r) => new AutoModerationRule(r));
3681
4764
  }
3682
4765
  async fetchAutoModerationRule(guildId, ruleId) {
3683
- const rule = await this.#rest.get(Routes.guildAutoModerationRule(guildId, ruleId));
3684
- return new AutoModerationRule(rule);
3685
- }
3686
- async createAutoModerationRule(guildId, options) {
3687
- const rule = await this.#rest.post(Routes.guildAutoModerationRules(guildId), options);
3688
- return new AutoModerationRule(rule);
3689
- }
3690
- async editAutoModerationRule(guildId, ruleId, options) {
3691
- const rule = await this.#rest.patch(Routes.guildAutoModerationRule(guildId, ruleId), options);
3692
- return new AutoModerationRule(rule);
3693
- }
3694
- async deleteAutoModerationRule(guildId, ruleId) {
3695
- await this.#rest.delete(Routes.guildAutoModerationRule(guildId, ruleId));
3696
- }
3697
- }
3698
- var AuditLogEvent = {
3699
- GuildUpdate: 1,
3700
- ChannelCreate: 10,
3701
- ChannelUpdate: 11,
3702
- ChannelDelete: 12,
3703
- ChannelOverwriteCreate: 13,
3704
- ChannelOverwriteUpdate: 14,
3705
- ChannelOverwriteDelete: 15,
3706
- MemberKick: 20,
3707
- MemberPrune: 21,
3708
- MemberBanAdd: 22,
3709
- MemberBanRemove: 23,
3710
- MemberUpdate: 24,
3711
- MemberRoleUpdate: 25,
3712
- MemberMove: 26,
3713
- MemberDisconnect: 27,
3714
- BotAdd: 28,
3715
- RoleCreate: 30,
3716
- RoleUpdate: 31,
3717
- RoleDelete: 32,
3718
- InviteCreate: 40,
3719
- InviteUpdate: 41,
3720
- InviteDelete: 42,
3721
- WebhookCreate: 50,
3722
- WebhookUpdate: 51,
3723
- WebhookDelete: 52,
3724
- EmojiCreate: 60,
3725
- EmojiUpdate: 61,
3726
- EmojiDelete: 62,
3727
- MessageDelete: 72,
3728
- MessageBulkDelete: 73,
3729
- MessagePin: 74,
3730
- MessageUnpin: 75,
3731
- IntegrationCreate: 80,
3732
- IntegrationUpdate: 81,
3733
- IntegrationDelete: 82,
3734
- StageInstanceCreate: 83,
3735
- StageInstanceUpdate: 84,
3736
- StageInstanceDelete: 85,
3737
- StickerCreate: 90,
3738
- StickerUpdate: 91,
3739
- StickerDelete: 92,
3740
- ScheduledEventCreate: 100,
3741
- ScheduledEventUpdate: 101,
3742
- ScheduledEventDelete: 102,
3743
- ThreadCreate: 110,
3744
- ThreadUpdate: 111,
3745
- ThreadDelete: 112,
3746
- AutoModerationRuleCreate: 140,
3747
- AutoModerationRuleUpdate: 141,
3748
- AutoModerationRuleDelete: 142,
3749
- AutoModerationBlockMessage: 143
3750
- };
3751
- // packages/managers/src/role.ts
3752
- class RoleManager extends ResourceManager {
3753
- #rest;
3754
- guildId;
3755
- constructor(guildId, rest) {
3756
- super((id) => rest.get(Routes.guildRole(guildId, id)).then((data) => new Role(data)), (role) => role.id);
3757
- this.guildId = guildId;
3758
- this.#rest = rest;
3759
- }
3760
- async fetchAll() {
3761
- const data = await this.#rest.get(Routes.guildRoles(this.guildId));
3762
- return data.map((item) => {
3763
- const role = new Role(item);
3764
- this.set(role.id, role);
3765
- return role;
3766
- });
3767
- }
3768
- async create(options) {
3769
- const { reason, ...payload } = options;
3770
- const data = await this.#rest.post(Routes.guildRoles(this.guildId), {
3771
- ...payload,
3772
- permissions: payload.permissions !== undefined ? String(payload.permissions) : undefined
3773
- });
3774
- const role = new Role(data);
3775
- this.set(role.id, role);
3776
- return role;
3777
- }
3778
- async edit(roleId, options) {
3779
- const { reason, ...payload } = options;
3780
- const data = await this.#rest.patch(Routes.guildRole(this.guildId, roleId), {
3781
- ...payload,
3782
- permissions: payload.permissions !== undefined ? String(payload.permissions) : undefined
3783
- });
3784
- const role = new Role(data);
3785
- this.set(role.id, role);
3786
- return role;
3787
- }
3788
- async deleteRole(roleId) {
3789
- await this.#rest.delete(Routes.guildRole(this.guildId, roleId));
3790
- this.delete(roleId);
3791
- }
3792
- }
3793
- // packages/managers/src/member.ts
3794
- class GuildMemberManager extends ResourceManager {
3795
- #rest;
3796
- guildId;
3797
- constructor(guildId, rest) {
3798
- super((id) => rest.get(Routes.guildMember(guildId, id)).then((data) => new GuildMember({ ...data, guild_id: guildId })), (member) => member.user.id);
3799
- this.guildId = guildId;
3800
- this.#rest = rest;
3801
- }
3802
- async kick(userId) {
3803
- await this.#rest.delete(Routes.guildMember(this.guildId, userId));
3804
- this.delete(userId);
3805
- }
3806
- async ban(userId, options = {}) {
3807
- await this.#rest.put(Routes.guildBan(this.guildId, userId), { delete_message_seconds: options.deleteMessageSeconds }, { reason: options.reason });
3808
- this.delete(userId);
3809
- }
3810
- async unban(userId) {
3811
- await this.#rest.delete(Routes.guildBan(this.guildId, userId));
3812
- }
3813
- async edit(userId, options) {
3814
- const data = await this.#rest.patch(Routes.guildMember(this.guildId, userId), options);
3815
- const member = new GuildMember({ ...data, guild_id: this.guildId });
3816
- this.set(member.user.id, member);
3817
- return member;
4766
+ const rule = await this.#rest.get(Routes.guildAutoModerationRule(guildId, ruleId));
4767
+ return new AutoModerationRule(rule);
3818
4768
  }
3819
- async addRole(userId, roleId) {
3820
- await this.#rest.put(Routes.guildMemberRole(this.guildId, userId, roleId));
4769
+ async createAutoModerationRule(guildId, options) {
4770
+ const rule = await this.#rest.post(Routes.guildAutoModerationRules(guildId), options);
4771
+ return new AutoModerationRule(rule);
3821
4772
  }
3822
- async removeRole(userId, roleId) {
3823
- await this.#rest.delete(Routes.guildMemberRole(this.guildId, userId, roleId));
4773
+ async editAutoModerationRule(guildId, ruleId, options) {
4774
+ const rule = await this.#rest.patch(Routes.guildAutoModerationRule(guildId, ruleId), options);
4775
+ return new AutoModerationRule(rule);
3824
4776
  }
3825
- async timeout(userId, milliseconds) {
3826
- const timeoutDate = milliseconds === null ? null : new Date(Date.now() + milliseconds).toISOString();
3827
- return this.edit(userId, { communication_disabled_until: timeoutDate });
4777
+ async deleteAutoModerationRule(guildId, ruleId) {
4778
+ await this.#rest.delete(Routes.guildAutoModerationRule(guildId, ruleId));
3828
4779
  }
3829
4780
  }
4781
+ var AuditLogEvent = {
4782
+ GuildUpdate: 1,
4783
+ ChannelCreate: 10,
4784
+ ChannelUpdate: 11,
4785
+ ChannelDelete: 12,
4786
+ ChannelOverwriteCreate: 13,
4787
+ ChannelOverwriteUpdate: 14,
4788
+ ChannelOverwriteDelete: 15,
4789
+ MemberKick: 20,
4790
+ MemberPrune: 21,
4791
+ MemberBanAdd: 22,
4792
+ MemberBanRemove: 23,
4793
+ MemberUpdate: 24,
4794
+ MemberRoleUpdate: 25,
4795
+ MemberMove: 26,
4796
+ MemberDisconnect: 27,
4797
+ BotAdd: 28,
4798
+ RoleCreate: 30,
4799
+ RoleUpdate: 31,
4800
+ RoleDelete: 32,
4801
+ InviteCreate: 40,
4802
+ InviteUpdate: 41,
4803
+ InviteDelete: 42,
4804
+ WebhookCreate: 50,
4805
+ WebhookUpdate: 51,
4806
+ WebhookDelete: 52,
4807
+ EmojiCreate: 60,
4808
+ EmojiUpdate: 61,
4809
+ EmojiDelete: 62,
4810
+ MessageDelete: 72,
4811
+ MessageBulkDelete: 73,
4812
+ MessagePin: 74,
4813
+ MessageUnpin: 75,
4814
+ IntegrationCreate: 80,
4815
+ IntegrationUpdate: 81,
4816
+ IntegrationDelete: 82,
4817
+ StageInstanceCreate: 83,
4818
+ StageInstanceUpdate: 84,
4819
+ StageInstanceDelete: 85,
4820
+ StickerCreate: 90,
4821
+ StickerUpdate: 91,
4822
+ StickerDelete: 92,
4823
+ ScheduledEventCreate: 100,
4824
+ ScheduledEventUpdate: 101,
4825
+ ScheduledEventDelete: 102,
4826
+ ThreadCreate: 110,
4827
+ ThreadUpdate: 111,
4828
+ ThreadDelete: 112,
4829
+ AutoModerationRuleCreate: 140,
4830
+ AutoModerationRuleUpdate: 141,
4831
+ AutoModerationRuleDelete: 142,
4832
+ AutoModerationBlockMessage: 143
4833
+ };
3830
4834
  // packages/managers/src/application.ts
3831
4835
  class ApplicationCommandManager {
3832
4836
  #rest;
@@ -3866,53 +4870,22 @@ class ApplicationCommandManager {
3866
4870
  await this.#rest.delete(Routes.guildApplicationCommand(this.#applicationId, guildId, commandId));
3867
4871
  }
3868
4872
  }
3869
- // packages/managers/src/emoji.ts
3870
- class EmojiManager extends Manager {
3871
- #rest;
3872
- #guildId;
3873
- constructor(rest, guildId) {
3874
- super();
3875
- this.#rest = rest;
3876
- this.#guildId = guildId;
3877
- }
3878
- async fetch(emojiId) {
3879
- return this.upsert(await this.#rest.get(Routes.guildEmoji(this.#guildId, emojiId)));
3880
- }
3881
- async fetchAll() {
3882
- const data = await this.#rest.get(Routes.guildEmoji(this.#guildId));
3883
- return data.map((item) => this.upsert(item));
3884
- }
3885
- async create(options) {
3886
- return this.upsert(await this.#rest.post(Routes.guildEmoji(this.#guildId), options));
3887
- }
3888
- async edit(emojiId, options) {
3889
- return this.upsert(await this.#rest.patch(Routes.guildEmoji(this.#guildId, emojiId), options));
3890
- }
3891
- async deleteEmoji(emojiId) {
3892
- await this.#rest.delete(Routes.guildEmoji(this.#guildId, emojiId));
3893
- this.delete(emojiId);
3894
- }
3895
- upsert(data) {
3896
- const key = data.id != null ? data.id : `unicode:${data.name ?? ""}`;
3897
- const existing = this.get(key);
3898
- const emoji = new Emoji(data);
3899
- if (existing) {
3900
- Object.assign(existing, emoji);
3901
- return existing;
3902
- }
3903
- this.set(key, emoji);
3904
- return emoji;
3905
- }
3906
- }
3907
4873
 
3908
4874
  // packages/managers/src/index.ts
4875
+ var BULK_DELETE_MAX_AGE_MS = 14 * 24 * 60 * 60000;
4876
+ function snowflakeTime(id) {
4877
+ return Number((BigInt(id) >> 22n) + 1420070400000n);
4878
+ }
4879
+
3909
4880
  class ChannelManager extends Manager {
3910
4881
  #rest;
3911
4882
  #context;
3912
4883
  #messageManagers = new Map;
3913
- constructor(rest) {
4884
+ #messageCache;
4885
+ constructor(rest, options = {}) {
3914
4886
  super();
3915
4887
  this.#rest = rest;
4888
+ this.#messageCache = options.messageCache;
3916
4889
  this.#context = {
3917
4890
  sendMessage: (channelId, options) => this.send(channelId, options),
3918
4891
  editMessage: (channelId, messageId, options) => this.editMessage(channelId, messageId, options),
@@ -3931,27 +4904,29 @@ class ChannelManager extends Manager {
3931
4904
  messages(channelId) {
3932
4905
  let manager = this.#messageManagers.get(channelId);
3933
4906
  if (!manager) {
3934
- manager = new MessageManager(this.#rest, this.#context, channelId);
4907
+ manager = new MessageManager(this.#rest, this.#context, channelId, this.#messageCache);
3935
4908
  this.#messageManagers.set(channelId, manager);
3936
4909
  }
3937
4910
  return manager;
3938
4911
  }
3939
4912
  permissionOverwrites(channelId) {
3940
- return new PermissionOverwriteManager(this.#rest, channelId);
4913
+ return new PermissionOverwriteManager(this.#rest, channelId, () => this.get(channelId)?.permissionOverwrites);
3941
4914
  }
3942
4915
  threads(channelId) {
3943
4916
  return new ThreadManager(this.#rest, this.#context, channelId);
3944
4917
  }
3945
- async fetch(channelId) {
3946
- return this.upsert(await this.#rest.get(Routes.channel(channelId)));
4918
+ fetch(channelId) {
4919
+ return this.fetchOnce(channelId, async () => createChannel(await this.#rest.get(Routes.channel(channelId)), this.#context), (channel) => this.#merge(channel));
3947
4920
  }
3948
4921
  async resolve(channelId) {
3949
4922
  return this.get(channelId) ?? this.fetch(channelId);
3950
4923
  }
3951
4924
  upsert(data) {
3952
- const existing = this.get(data.id);
3953
- const channel = createChannel(data, this.#context);
3954
- if (existing) {
4925
+ return this.#merge(createChannel(data, this.#context));
4926
+ }
4927
+ #merge(channel) {
4928
+ const existing = this.get(channel.id);
4929
+ if (existing && existing.type === channel.type) {
3955
4930
  Object.assign(existing, channel);
3956
4931
  return existing;
3957
4932
  }
@@ -3961,6 +4936,37 @@ class ChannelManager extends Manager {
3961
4936
  update(channel) {
3962
4937
  return this.set(channel.id, channel);
3963
4938
  }
4939
+ deleteGuildChannels(guildId) {
4940
+ let removed = 0;
4941
+ for (const channel of this.values())
4942
+ if (channel.guildId === guildId && this.delete(channel.id))
4943
+ removed++;
4944
+ return removed;
4945
+ }
4946
+ async endPoll(channelId, messageId) {
4947
+ return this.messages(channelId).upsert(await this.#rest.post(Routes.pollExpire(channelId, messageId)));
4948
+ }
4949
+ async fetchPollVoters(channelId, messageId, answerId, options = {}) {
4950
+ if (options.limit !== undefined && (!Number.isInteger(options.limit) || options.limit < 1 || options.limit > 100))
4951
+ throw new RangeError("Poll voter limit must be 1-100.");
4952
+ const params = new URLSearchParams;
4953
+ if (options.after)
4954
+ params.set("after", options.after);
4955
+ if (options.limit !== undefined)
4956
+ params.set("limit", String(options.limit));
4957
+ const suffix = params.toString();
4958
+ const { users } = await this.#rest.get(`${Routes.pollAnswerVoters(channelId, messageId, answerId)}${suffix ? `?${suffix}` : ""}`);
4959
+ return users.map((user) => new User(user));
4960
+ }
4961
+ async sendSoundboardSound(channelId, options) {
4962
+ await this.#rest.post(Routes.sendSoundboardSound(channelId), {
4963
+ sound_id: options.soundId,
4964
+ source_guild_id: options.sourceGuildId
4965
+ });
4966
+ }
4967
+ cachedMessages(channelId) {
4968
+ return this.#messageManagers.get(channelId);
4969
+ }
3964
4970
  async create(guildId, options) {
3965
4971
  return this.upsert(await this.#rest.post(Routes.guildChannels(guildId), options));
3966
4972
  }
@@ -4004,7 +5010,7 @@ class ChannelManager extends Manager {
4004
5010
  return this.messages(data.channel_id).upsert(data);
4005
5011
  }
4006
5012
  async editMessage(channelId, messageId, options) {
4007
- return this.messages(channelId).upsert(await this.#rest.patch(Routes.message(channelId, messageId), options));
5013
+ return this.messages(channelId).upsert(await this.#rest.patch(Routes.message(channelId, messageId), toRequest(options)));
4008
5014
  }
4009
5015
  async deleteMessage(channelId, messageId) {
4010
5016
  await this.#rest.delete(Routes.message(channelId, messageId));
@@ -4017,15 +5023,37 @@ class ChannelManager extends Manager {
4017
5023
  return this.messages(channelId).upsert(await this.#rest.post(Routes.crosspostMessage(channelId, messageId)));
4018
5024
  }
4019
5025
  async bulkDeleteMessages(channelId, messageIds) {
4020
- const ids = [...messageIds];
4021
- if (ids.length < 2 || ids.length > 100)
4022
- throw new RangeError("bulkDelete requires between 2 and 100 message IDs.");
5026
+ const ids = [...new Set(messageIds)];
5027
+ if (ids.length < 1 || ids.length > 100)
5028
+ throw new RangeError("bulkDelete requires between 1 and 100 message IDs.");
5029
+ if (ids.length === 1)
5030
+ return this.deleteMessage(channelId, ids[0]);
5031
+ const cutoff = Date.now() - BULK_DELETE_MAX_AGE_MS;
5032
+ const tooOld = ids.filter((id) => snowflakeTime(id) < cutoff);
5033
+ if (tooOld.length)
5034
+ throw new RangeError(`bulkDelete cannot delete messages older than 14 days: ${tooOld.join(", ")}`);
4023
5035
  await this.#rest.post(Routes.channelBulkDelete(channelId), {
4024
5036
  messages: ids
4025
5037
  });
4026
5038
  for (const id of ids)
4027
5039
  this.messages(channelId).delete(id);
4028
5040
  }
5041
+ async* iterateMessages(channelId, options = {}) {
5042
+ let before = options.before;
5043
+ let remaining = options.limit ?? Infinity;
5044
+ while (remaining > 0) {
5045
+ const page = await this.fetchMessages(channelId, {
5046
+ before,
5047
+ limit: Math.min(100, remaining)
5048
+ });
5049
+ for (const message of page)
5050
+ yield message;
5051
+ remaining -= page.length;
5052
+ if (page.length < 100)
5053
+ return;
5054
+ before = page.at(-1).id;
5055
+ }
5056
+ }
4029
5057
  async addReaction(channelId, messageId, emoji) {
4030
5058
  await this.#rest.put(`${Routes.messageReactions(channelId, messageId, emoji)}/@me`);
4031
5059
  }
@@ -4121,6 +5149,8 @@ class GatewaySession {
4121
5149
  return false;
4122
5150
  if (!Number.isInteger(sequence))
4123
5151
  return false;
5152
+ if (this.#sequence !== null && sequence < this.#sequence)
5153
+ return false;
4124
5154
  this.#sequence = sequence;
4125
5155
  return true;
4126
5156
  }
@@ -4219,8 +5249,11 @@ class GatewayHeartbeat {
4219
5249
  this.#clearBeatTimers();
4220
5250
  this.#interval = interval;
4221
5251
  this.#acknowledged = true;
4222
- this.#initialTimer = setTimeout(() => this.sendHeartbeat(), Math.random() * interval);
4223
- this.#timer = setInterval(() => this.sendHeartbeat(), interval);
5252
+ this.#initialTimer = setTimeout(() => {
5253
+ this.#initialTimer = undefined;
5254
+ this.sendHeartbeat();
5255
+ this.#timer = setInterval(() => this.sendHeartbeat(), interval);
5256
+ }, Math.random() * interval);
4224
5257
  }
4225
5258
  stop() {
4226
5259
  this.#clearBeatTimers();
@@ -4246,6 +5279,8 @@ class GatewayHeartbeat {
4246
5279
  }, this.#options.ackTimeout);
4247
5280
  }
4248
5281
  acknowledge() {
5282
+ if (this.#acknowledged)
5283
+ return;
4249
5284
  this.#acknowledged = true;
4250
5285
  this.#latency = this.#now() - this.#sentAt;
4251
5286
  this.#clearAckTimer();
@@ -4826,6 +5861,7 @@ class SendBudget {
4826
5861
  }
4827
5862
 
4828
5863
  // packages/ws/src/index.ts
5864
+ var RESUMABLE_CLOSE_CODE = 4900;
4829
5865
  var DEFAULT_GATEWAY_URL = "wss://gateway.discord.gg/?v=10&encoding=json";
4830
5866
 
4831
5867
  class Gateway {
@@ -4911,7 +5947,7 @@ class Gateway {
4911
5947
  } else {
4912
5948
  this.#emitError(new GatewayError(`Gateway heartbeat acknowledgement timed out after ${timeout.elapsedMs}ms.`));
4913
5949
  }
4914
- this.#transport.close(1001, timeout.type === "zombie" ? "Zombie Gateway connection" : "Heartbeat timeout");
5950
+ this.#transport.close(RESUMABLE_CLOSE_CODE, timeout.type === "zombie" ? "Zombie Gateway connection" : "Heartbeat timeout");
4915
5951
  }
4916
5952
  connect(url = DEFAULT_GATEWAY_URL) {
4917
5953
  if (this.state === "CLOSED" /* Closed */)
@@ -5047,7 +6083,7 @@ class Gateway {
5047
6083
  this.#emit("heartbeatAck", action.data);
5048
6084
  return;
5049
6085
  case "reconnect":
5050
- this.#transport.close(1001, "Server requested reconnect");
6086
+ this.#transport.close(RESUMABLE_CLOSE_CODE, "Server requested reconnect");
5051
6087
  return;
5052
6088
  case "invalid-session": {
5053
6089
  if (!action.resumable)
@@ -5241,6 +6277,7 @@ class Client extends EventEmitter2 {
5241
6277
  channels;
5242
6278
  stageInstances;
5243
6279
  application;
6280
+ monetization;
5244
6281
  get ws() {
5245
6282
  return this.#gateway;
5246
6283
  }
@@ -5272,6 +6309,7 @@ class Client extends EventEmitter2 {
5272
6309
  return this.#gateway.requestGuildMembers(data);
5273
6310
  }
5274
6311
  #gateway;
6312
+ #cache;
5275
6313
  #resourceContext;
5276
6314
  constructor(options) {
5277
6315
  super();
@@ -5279,9 +6317,18 @@ class Client extends EventEmitter2 {
5279
6317
  if (!options.token?.trim())
5280
6318
  throw new TypeError("Client token is required.");
5281
6319
  this.rest = new REST({ token: options.token, ...options.rest });
6320
+ this.#cache = {
6321
+ users: true,
6322
+ members: true,
6323
+ roles: true,
6324
+ emojis: true,
6325
+ ...options.cache
6326
+ };
5282
6327
  this.users = new UserManager(this.rest);
5283
6328
  this.guilds = new GuildManager(this.rest);
5284
- this.channels = new ChannelManager(this.rest);
6329
+ this.channels = new ChannelManager(this.rest, {
6330
+ messageCache: options.messageCache
6331
+ });
5285
6332
  this.stageInstances = new StageInstanceManager(this.rest);
5286
6333
  const placeholderAppCommands = new ApplicationCommandManager(this.rest, "0");
5287
6334
  this.application = { commands: placeholderAppCommands };
@@ -5297,8 +6344,32 @@ class Client extends EventEmitter2 {
5297
6344
  removeReaction: (channelId, messageId, emoji, userId) => this.channels.removeReaction(channelId, messageId, emoji, userId),
5298
6345
  removeAllReactions: (channelId, messageId) => this.channels.removeAllReactions(channelId, messageId),
5299
6346
  pinMessage: (channelId, messageId) => this.channels.pinMessage(channelId, messageId),
5300
- unpinMessage: (channelId, messageId) => this.channels.unpinMessage(channelId, messageId)
6347
+ unpinMessage: (channelId, messageId) => this.channels.unpinMessage(channelId, messageId),
6348
+ collectInteractions: (options) => this.createCollector("interactionCreate" /* InteractionCreate */, options),
6349
+ memberPermissions: (guildId, memberId, roleIds, channelId) => this.#memberPermissions(guildId, memberId, roleIds, channelId),
6350
+ kickMember: (guildId, userId, reason) => this.guilds.members(guildId).kick(userId, reason),
6351
+ banMember: (guildId, userId, options) => this.guilds.members(guildId).ban(userId, options),
6352
+ editMember: (guildId, userId, options, reason) => this.guilds.members(guildId).edit(userId, options, reason),
6353
+ addMemberRole: (guildId, userId, roleId, reason) => this.guilds.members(guildId).addRole(userId, roleId, reason),
6354
+ removeMemberRole: (guildId, userId, roleId, reason) => this.guilds.members(guildId).removeRole(userId, roleId, reason),
6355
+ editPermissionOverwrite: async (channelId, targetId, changes, options) => {
6356
+ const bits = { allow: 0n, deny: 0n, inherit: 0n };
6357
+ for (const [name, value] of Object.entries(changes)) {
6358
+ if (!/^[A-Za-z]+$/.test(name))
6359
+ throw new TypeError(`Unknown permission: ${name}`);
6360
+ let bit;
6361
+ try {
6362
+ bit = new PermissionSet(name).bitfield;
6363
+ } catch {
6364
+ throw new TypeError(`Unknown permission: ${name}`);
6365
+ }
6366
+ const key = value === true ? "allow" : value === false ? "deny" : "inherit";
6367
+ bits[key] |= bit;
6368
+ }
6369
+ return this.channels.permissionOverwrites(channelId).update(targetId, bits, options);
6370
+ }
5301
6371
  };
6372
+ this.guilds.attachContext(this.#resourceContext);
5302
6373
  this.#gateway = new Gateway({
5303
6374
  token: options.token,
5304
6375
  intents: options.intents,
@@ -5312,6 +6383,8 @@ class Client extends EventEmitter2 {
5312
6383
  this.state = "ready";
5313
6384
  const appId = ready.application?.id ?? this.user.id;
5314
6385
  this.application.commands = new ApplicationCommandManager(this.rest, appId);
6386
+ if (this.monetization?.applicationId !== appId)
6387
+ this.monetization = new MonetizationManager(this.rest, appId);
5315
6388
  this.emit("ready" /* Ready */, this.user);
5316
6389
  });
5317
6390
  this.#gateway.on("RESUMED", () => {
@@ -5328,19 +6401,46 @@ class Client extends EventEmitter2 {
5328
6401
  this.emit("close" /* Close */, data);
5329
6402
  });
5330
6403
  this.#gateway.on("MESSAGE_CREATE", (data) => {
5331
- const message = new Message(data, this.#resourceContext);
5332
- this.channels.set(message.channelId, message.channel);
5333
- this.users.set(message.author.id, message.author);
5334
- this.emit("messageCreate" /* MessageCreate */, message);
6404
+ const payload = data;
6405
+ const message = new Message(payload, this.#resourceContext);
6406
+ this.#observeMessage(message);
6407
+ if (payload.member && payload.guild_id && this.guilds.has(payload.guild_id))
6408
+ this.#upsertMember(payload.guild_id, {
6409
+ ...payload.member,
6410
+ user: payload.member.user ?? payload.author
6411
+ });
6412
+ const cached = this.options.messageCache ? this.channels.messages(message.channelId).upsert(data) : message;
6413
+ this.emit("messageCreate" /* MessageCreate */, cached);
5335
6414
  });
5336
6415
  this.#gateway.on("MESSAGE_UPDATE", (data) => {
5337
6416
  const message = new Message(data, this.#resourceContext);
5338
- this.channels.set(message.channelId, message.channel);
5339
- this.users.set(message.author.id, message.author);
5340
- this.emit("messageUpdate" /* MessageUpdate */, message);
6417
+ this.#observeMessage(message);
6418
+ const messages = this.channels.cachedMessages(message.channelId);
6419
+ const previous = messages?.cache.peek(message.id);
6420
+ if (previous)
6421
+ messages.cache.set(message.id, message);
6422
+ this.emit("messageUpdate" /* MessageUpdate */, message, previous);
6423
+ });
6424
+ this.#gateway.on("MESSAGE_DELETE", (data) => {
6425
+ const payload = data;
6426
+ const messages = this.channels.cachedMessages(payload.channel_id);
6427
+ const removed = messages?.cache.peek(payload.id);
6428
+ messages?.delete(payload.id);
6429
+ this.emit("messageDelete" /* MessageDelete */, payload, removed);
6430
+ });
6431
+ this.#gateway.on("MESSAGE_DELETE_BULK", (data) => {
6432
+ const payload = data;
6433
+ const messages = this.channels.cachedMessages(payload.channel_id);
6434
+ const removed = [];
6435
+ if (messages)
6436
+ for (const id of payload.ids) {
6437
+ const message = messages.cache.peek(id);
6438
+ if (message)
6439
+ removed.push(message);
6440
+ messages.delete(id);
6441
+ }
6442
+ this.emit("messageDeleteBulk" /* MessageDeleteBulk */, payload, removed);
5341
6443
  });
5342
- this.#gateway.on("MESSAGE_DELETE", (data) => this.emit("messageDelete" /* MessageDelete */, data));
5343
- this.#gateway.on("MESSAGE_DELETE_BULK", (data) => this.emit("messageDeleteBulk" /* MessageDeleteBulk */, data));
5344
6444
  this.#gateway.on("MESSAGE_REACTION_ADD", (data) => this.emit("messageReactionAdd" /* MessageReactionAdd */, data));
5345
6445
  this.#gateway.on("MESSAGE_REACTION_REMOVE", (data) => this.emit("messageReactionRemove" /* MessageReactionRemove */, data));
5346
6446
  this.#gateway.on("MESSAGE_REACTION_REMOVE_ALL", (data) => this.emit("messageReactionRemoveAll" /* MessageReactionRemoveAll */, data));
@@ -5354,20 +6454,27 @@ class Client extends EventEmitter2 {
5354
6454
  return;
5355
6455
  }
5356
6456
  const wasCached = this.guilds.has(payload.id);
5357
- const guild = new Guild(payload);
5358
- this.guilds.set(guild.id, guild);
6457
+ this.guilds.patch(payload);
6458
+ for (const role of payload.roles ?? [])
6459
+ this.#upsertRole(payload.id, role);
6460
+ if (this.#cache.emojis) {
6461
+ const emojis = this.guilds.emojis(payload.id);
6462
+ for (const emoji of payload.emojis ?? [])
6463
+ emojis.upsert(emoji);
6464
+ }
5359
6465
  for (const member of payload.members ?? [])
5360
- this.users.set(member.user.id, new User(member.user));
6466
+ this.#upsertMember(payload.id, member);
6467
+ for (const state of payload.voice_states ?? [])
6468
+ this.#storeVoiceState(payload.id, state);
5361
6469
  for (const channelData of [
5362
6470
  ...payload.channels ?? [],
5363
6471
  ...payload.threads ?? []
5364
6472
  ])
5365
- this.channels.set(channelData.id, createChannel(channelData, this.#resourceContext));
6473
+ this.channels.upsert({ ...channelData, guild_id: payload.id });
5366
6474
  this.emit(wasCached ? "guildAvailable" /* GuildAvailable */ : "guildCreate" /* GuildCreate */, payload);
5367
6475
  });
5368
6476
  this.#gateway.on("GUILD_UPDATE", (data) => {
5369
- const guild = new Guild(data);
5370
- this.guilds.update(guild);
6477
+ this.guilds.patch(data);
5371
6478
  this.emit("guildUpdate" /* GuildUpdate */, data);
5372
6479
  });
5373
6480
  this.#gateway.on("GUILD_DELETE", (data) => {
@@ -5377,45 +6484,158 @@ class Client extends EventEmitter2 {
5377
6484
  return;
5378
6485
  }
5379
6486
  this.guilds.delete(payload.id);
6487
+ this.channels.deleteGuildChannels(payload.id);
5380
6488
  this.emit("guildDelete" /* GuildDelete */, payload);
5381
6489
  });
5382
6490
  this.#gateway.on("GUILD_MEMBER_ADD", (data) => {
5383
6491
  const member = data;
5384
- this.users.set(member.user.id, new User(member.user));
6492
+ this.#upsertMember(member.guild_id, member);
5385
6493
  this.emit("guildMemberAdd" /* GuildMemberAdd */, member);
5386
6494
  });
5387
6495
  this.#gateway.on("GUILD_MEMBER_UPDATE", (data) => {
5388
6496
  const member = data;
5389
- this.users.set(member.user.id, new User(member.user));
6497
+ this.#upsertMember(member.guild_id, member);
5390
6498
  this.emit("guildMemberUpdate" /* GuildMemberUpdate */, member);
5391
6499
  });
5392
- this.#gateway.on("GUILD_MEMBER_REMOVE", (data) => this.emit("guildMemberRemove" /* GuildMemberRemove */, data));
5393
- this.#gateway.on("GUILD_MEMBERS_CHUNK", (data) => this.emit("guildMembersChunk" /* GuildMembersChunk */, data));
5394
- this.#gateway.on("GUILD_BAN_ADD", (data) => this.emit("guildBanAdd" /* GuildBanAdd */, data));
5395
- this.#gateway.on("GUILD_BAN_REMOVE", (data) => this.emit("guildBanRemove" /* GuildBanRemove */, data));
5396
- this.#gateway.on("GUILD_ROLE_CREATE", (data) => this.emit("guildRoleCreate" /* GuildRoleCreate */, data));
5397
- this.#gateway.on("GUILD_ROLE_UPDATE", (data) => this.emit("guildRoleUpdate" /* GuildRoleUpdate */, data));
5398
- this.#gateway.on("GUILD_ROLE_DELETE", (data) => this.emit("guildRoleDelete" /* GuildRoleDelete */, data));
5399
- this.#gateway.on("GUILD_EMOJIS_UPDATE", (data) => this.emit("guildEmojisUpdate" /* GuildEmojisUpdate */, data));
5400
- this.#gateway.on("GUILD_STICKERS_UPDATE", (data) => this.emit("guildStickersUpdate" /* GuildStickersUpdate */, data));
6500
+ this.#gateway.on("GUILD_MEMBER_REMOVE", (data) => {
6501
+ const member = data;
6502
+ this.guilds.members(member.guild_id).delete(member.user.id);
6503
+ this.emit("guildMemberRemove" /* GuildMemberRemove */, member);
6504
+ });
6505
+ this.#gateway.on("GUILD_MEMBERS_CHUNK", (data) => {
6506
+ const chunk = data;
6507
+ for (const member of chunk.members)
6508
+ this.#upsertMember(chunk.guild_id, member);
6509
+ this.emit("guildMembersChunk" /* GuildMembersChunk */, chunk);
6510
+ });
6511
+ this.#gateway.on("GUILD_BAN_ADD", (data) => {
6512
+ const ban = data;
6513
+ const bans = this.guilds.bans(ban.guild_id);
6514
+ bans.set(ban.user.id, {
6515
+ reason: bans.get(ban.user.id)?.reason ?? null,
6516
+ user: ban.user
6517
+ });
6518
+ this.guilds.members(ban.guild_id).delete(ban.user.id);
6519
+ this.emit("guildBanAdd" /* GuildBanAdd */, ban);
6520
+ });
6521
+ this.#gateway.on("GUILD_BAN_REMOVE", (data) => {
6522
+ const ban = data;
6523
+ this.guilds.bans(ban.guild_id).delete(ban.user.id);
6524
+ this.emit("guildBanRemove" /* GuildBanRemove */, ban);
6525
+ });
6526
+ this.#gateway.on("GUILD_ROLE_CREATE", (data) => {
6527
+ const event = data;
6528
+ this.#upsertRole(event.guild_id, event.role);
6529
+ this.emit("guildRoleCreate" /* GuildRoleCreate */, event);
6530
+ });
6531
+ this.#gateway.on("GUILD_ROLE_UPDATE", (data) => {
6532
+ const event = data;
6533
+ this.#upsertRole(event.guild_id, event.role);
6534
+ this.emit("guildRoleUpdate" /* GuildRoleUpdate */, event);
6535
+ });
6536
+ this.#gateway.on("GUILD_ROLE_DELETE", (data) => {
6537
+ const event = data;
6538
+ this.guilds.roles(event.guild_id).delete(event.role_id);
6539
+ this.emit("guildRoleDelete" /* GuildRoleDelete */, event);
6540
+ });
6541
+ this.#gateway.on("GUILD_EMOJIS_UPDATE", (data) => {
6542
+ const event = data;
6543
+ if (this.#cache.emojis) {
6544
+ const emojis = this.guilds.emojis(event.guild_id);
6545
+ const current = new Set(event.emojis.map((emoji) => emoji.id));
6546
+ for (const id of [...emojis.cache.keys()])
6547
+ if (!current.has(id))
6548
+ emojis.delete(id);
6549
+ for (const emoji of event.emojis)
6550
+ emojis.upsert(emoji);
6551
+ }
6552
+ this.emit("guildEmojisUpdate" /* GuildEmojisUpdate */, event);
6553
+ });
6554
+ this.#gateway.on("GUILD_STICKERS_UPDATE", (data) => {
6555
+ const event = data;
6556
+ this.guilds.stickers(event.guild_id).sync(event.stickers);
6557
+ this.emit("guildStickersUpdate" /* GuildStickersUpdate */, event);
6558
+ });
6559
+ this.#gateway.on("GUILD_SOUNDBOARD_SOUND_CREATE", (data) => {
6560
+ const sound = data;
6561
+ if (sound.guild_id)
6562
+ this.guilds.soundboard(sound.guild_id).set(sound.sound_id, sound);
6563
+ this.emit("soundboardSoundCreate" /* SoundboardSoundCreate */, sound);
6564
+ });
6565
+ this.#gateway.on("GUILD_SOUNDBOARD_SOUND_UPDATE", (data) => {
6566
+ const sound = data;
6567
+ if (sound.guild_id)
6568
+ this.guilds.soundboard(sound.guild_id).set(sound.sound_id, sound);
6569
+ this.emit("soundboardSoundUpdate" /* SoundboardSoundUpdate */, sound);
6570
+ });
6571
+ this.#gateway.on("GUILD_SOUNDBOARD_SOUND_DELETE", (data) => {
6572
+ const event = data;
6573
+ this.guilds.soundboard(event.guild_id).delete(event.sound_id);
6574
+ this.emit("soundboardSoundDelete" /* SoundboardSoundDelete */, event);
6575
+ });
6576
+ this.#gateway.on("GUILD_SOUNDBOARD_SOUNDS_UPDATE", (data) => {
6577
+ const event = data;
6578
+ const sounds = this.guilds.soundboard(event.guild_id);
6579
+ sounds.clear();
6580
+ for (const sound of event.soundboard_sounds)
6581
+ sounds.set(sound.sound_id, sound);
6582
+ this.emit("soundboardSoundsUpdate" /* SoundboardSoundsUpdate */, event);
6583
+ });
6584
+ this.#gateway.on("ENTITLEMENT_CREATE", (data) => {
6585
+ const entitlement = data;
6586
+ this.monetization?.set(entitlement.id, entitlement);
6587
+ this.emit("entitlementCreate" /* EntitlementCreate */, entitlement);
6588
+ });
6589
+ this.#gateway.on("ENTITLEMENT_UPDATE", (data) => {
6590
+ const entitlement = data;
6591
+ this.monetization?.set(entitlement.id, entitlement);
6592
+ this.emit("entitlementUpdate" /* EntitlementUpdate */, entitlement);
6593
+ });
6594
+ this.#gateway.on("ENTITLEMENT_DELETE", (data) => {
6595
+ const entitlement = data;
6596
+ this.monetization?.delete(entitlement.id);
6597
+ this.emit("entitlementDelete" /* EntitlementDelete */, entitlement);
6598
+ });
5401
6599
  this.#gateway.on("GUILD_INTEGRATIONS_UPDATE", (data) => this.emit("guildIntegrationsUpdate" /* GuildIntegrationsUpdate */, data));
5402
- this.#gateway.on("GUILD_SCHEDULED_EVENT_CREATE", (data) => this.emit("guildScheduledEventCreate" /* GuildScheduledEventCreate */, data));
5403
- this.#gateway.on("GUILD_SCHEDULED_EVENT_UPDATE", (data) => this.emit("guildScheduledEventUpdate" /* GuildScheduledEventUpdate */, data));
5404
- this.#gateway.on("GUILD_SCHEDULED_EVENT_DELETE", (data) => this.emit("guildScheduledEventDelete" /* GuildScheduledEventDelete */, data));
6600
+ this.#gateway.on("GUILD_SCHEDULED_EVENT_CREATE", (data) => {
6601
+ const event = data;
6602
+ this.guilds.scheduledEvents(event.guild_id).set(event.id, event);
6603
+ this.emit("guildScheduledEventCreate" /* GuildScheduledEventCreate */, event);
6604
+ });
6605
+ this.#gateway.on("GUILD_SCHEDULED_EVENT_UPDATE", (data) => {
6606
+ const event = data;
6607
+ this.guilds.scheduledEvents(event.guild_id).set(event.id, event);
6608
+ this.emit("guildScheduledEventUpdate" /* GuildScheduledEventUpdate */, event);
6609
+ });
6610
+ this.#gateway.on("GUILD_SCHEDULED_EVENT_DELETE", (data) => {
6611
+ const event = data;
6612
+ this.guilds.scheduledEvents(event.guild_id).delete(event.id);
6613
+ this.emit("guildScheduledEventDelete" /* GuildScheduledEventDelete */, event);
6614
+ });
5405
6615
  this.#gateway.on("GUILD_SCHEDULED_EVENT_USER_ADD", (data) => this.emit("guildScheduledEventUserAdd" /* GuildScheduledEventUserAdd */, data));
5406
6616
  this.#gateway.on("GUILD_SCHEDULED_EVENT_USER_REMOVE", (data) => this.emit("guildScheduledEventUserRemove" /* GuildScheduledEventUserRemove */, data));
5407
- this.#gateway.on("AUTO_MODERATION_RULE_CREATE", (data) => this.emit("autoModerationRuleCreate" /* AutoModerationRuleCreate */, data));
5408
- this.#gateway.on("AUTO_MODERATION_RULE_UPDATE", (data) => this.emit("autoModerationRuleUpdate" /* AutoModerationRuleUpdate */, data));
5409
- this.#gateway.on("AUTO_MODERATION_RULE_DELETE", (data) => this.emit("autoModerationRuleDelete" /* AutoModerationRuleDelete */, data));
6617
+ this.#gateway.on("AUTO_MODERATION_RULE_CREATE", (data) => {
6618
+ const rule = data;
6619
+ this.guilds.autoModerationRules(rule.guild_id).set(rule.id, rule);
6620
+ this.emit("autoModerationRuleCreate" /* AutoModerationRuleCreate */, rule);
6621
+ });
6622
+ this.#gateway.on("AUTO_MODERATION_RULE_UPDATE", (data) => {
6623
+ const rule = data;
6624
+ this.guilds.autoModerationRules(rule.guild_id).set(rule.id, rule);
6625
+ this.emit("autoModerationRuleUpdate" /* AutoModerationRuleUpdate */, rule);
6626
+ });
6627
+ this.#gateway.on("AUTO_MODERATION_RULE_DELETE", (data) => {
6628
+ const rule = data;
6629
+ this.guilds.autoModerationRules(rule.guild_id).delete(rule.id);
6630
+ this.emit("autoModerationRuleDelete" /* AutoModerationRuleDelete */, rule);
6631
+ });
5410
6632
  this.#gateway.on("AUTO_MODERATION_ACTION_EXECUTION", (data) => this.emit("autoModerationActionExecution" /* AutoModerationActionExecution */, data));
5411
6633
  this.#gateway.on("CHANNEL_CREATE", (data) => {
5412
- const channel = createChannel(data, this.#resourceContext);
5413
- this.channels.update(channel);
6634
+ const channel = this.channels.upsert(data);
5414
6635
  this.emit("channelCreate" /* ChannelCreate */, channel);
5415
6636
  });
5416
6637
  this.#gateway.on("CHANNEL_UPDATE", (data) => {
5417
- const channel = createChannel(data, this.#resourceContext);
5418
- this.channels.update(channel);
6638
+ const channel = this.channels.upsert(data);
5419
6639
  this.emit("channelUpdate" /* ChannelUpdate */, channel);
5420
6640
  });
5421
6641
  this.#gateway.on("CHANNEL_DELETE", (data) => {
@@ -5425,13 +6645,11 @@ class Client extends EventEmitter2 {
5425
6645
  });
5426
6646
  this.#gateway.on("CHANNEL_PINS_UPDATE", (data) => this.emit("channelPinsUpdate" /* ChannelPinsUpdate */, data));
5427
6647
  this.#gateway.on("THREAD_CREATE", (data) => {
5428
- const channel = createChannel(data, this.#resourceContext);
5429
- this.channels.update(channel);
6648
+ const channel = this.channels.upsert(data);
5430
6649
  this.emit("threadCreate" /* ThreadCreate */, channel);
5431
6650
  });
5432
6651
  this.#gateway.on("THREAD_UPDATE", (data) => {
5433
- const channel = createChannel(data, this.#resourceContext);
5434
- this.channels.update(channel);
6652
+ const channel = this.channels.upsert(data);
5435
6653
  this.emit("threadUpdate" /* ThreadUpdate */, channel);
5436
6654
  });
5437
6655
  this.#gateway.on("THREAD_DELETE", (data) => {
@@ -5439,16 +6657,48 @@ class Client extends EventEmitter2 {
5439
6657
  this.channels.delete(payload.id);
5440
6658
  this.emit("threadDelete" /* ThreadDelete */, payload);
5441
6659
  });
5442
- this.#gateway.on("THREAD_LIST_SYNC", (data) => this.emit("threadListSync" /* ThreadListSync */, data));
6660
+ this.#gateway.on("THREAD_LIST_SYNC", (data) => {
6661
+ const sync = data;
6662
+ for (const thread of sync.threads)
6663
+ this.channels.upsert({ ...thread, guild_id: sync.guild_id });
6664
+ this.emit("threadListSync" /* ThreadListSync */, sync);
6665
+ });
5443
6666
  this.#gateway.on("THREAD_MEMBERS_UPDATE", (data) => this.emit("threadMembersUpdate" /* ThreadMembersUpdate */, data));
5444
6667
  this.#gateway.on("THREAD_MEMBER_UPDATE", (data) => this.emit("threadMemberUpdate" /* ThreadMemberUpdate */, data));
5445
- this.#gateway.on("STAGE_INSTANCE_CREATE", (data) => this.emit("stageInstanceCreate" /* StageInstanceCreate */, data));
5446
- this.#gateway.on("STAGE_INSTANCE_UPDATE", (data) => this.emit("stageInstanceUpdate" /* StageInstanceUpdate */, data));
5447
- this.#gateway.on("STAGE_INSTANCE_DELETE", (data) => this.emit("stageInstanceDelete" /* StageInstanceDelete */, data));
5448
- this.#gateway.on("INVITE_CREATE", (data) => this.emit("inviteCreate" /* InviteCreate */, data));
5449
- this.#gateway.on("INVITE_DELETE", (data) => this.emit("inviteDelete" /* InviteDelete */, data));
6668
+ this.#gateway.on("STAGE_INSTANCE_CREATE", (data) => {
6669
+ const stage = data;
6670
+ this.stageInstances.set(stage.channel_id, stage);
6671
+ this.emit("stageInstanceCreate" /* StageInstanceCreate */, stage);
6672
+ });
6673
+ this.#gateway.on("STAGE_INSTANCE_UPDATE", (data) => {
6674
+ const stage = data;
6675
+ this.stageInstances.set(stage.channel_id, stage);
6676
+ this.emit("stageInstanceUpdate" /* StageInstanceUpdate */, stage);
6677
+ });
6678
+ this.#gateway.on("STAGE_INSTANCE_DELETE", (data) => {
6679
+ const stage = data;
6680
+ this.stageInstances.delete(stage.channel_id);
6681
+ this.emit("stageInstanceDelete" /* StageInstanceDelete */, stage);
6682
+ });
6683
+ this.#gateway.on("INVITE_CREATE", (data) => {
6684
+ const invite = data;
6685
+ if (invite.guild_id)
6686
+ this.guilds.invites(invite.guild_id).set(invite.code, invite);
6687
+ this.emit("inviteCreate" /* InviteCreate */, invite);
6688
+ });
6689
+ this.#gateway.on("INVITE_DELETE", (data) => {
6690
+ const invite = data;
6691
+ if (invite.guild_id)
6692
+ this.guilds.invites(invite.guild_id).delete(invite.code);
6693
+ this.emit("inviteDelete" /* InviteDelete */, invite);
6694
+ });
5450
6695
  this.#gateway.on("WEBHOOKS_UPDATE", (data) => this.emit("webhooksUpdate" /* WebhooksUpdate */, data));
5451
- this.#gateway.on("VOICE_STATE_UPDATE", (data) => this.emit("voiceStateUpdate" /* VoiceStateUpdate */, data));
6696
+ this.#gateway.on("VOICE_STATE_UPDATE", (data) => {
6697
+ const state = data;
6698
+ if (state.guild_id)
6699
+ this.#storeVoiceState(state.guild_id, state);
6700
+ this.emit("voiceStateUpdate" /* VoiceStateUpdate */, state);
6701
+ });
5452
6702
  this.#gateway.on("VOICE_SERVER_UPDATE", (data) => this.emit("voiceServerUpdate" /* VoiceServerUpdate */, data));
5453
6703
  this.#gateway.on("PRESENCE_UPDATE", (data) => this.emit("presenceUpdate" /* PresenceUpdate */, data));
5454
6704
  this.#gateway.on("TYPING_START", (data) => this.emit("typingStart" /* TypingStart */, data));
@@ -5456,6 +6706,103 @@ class Client extends EventEmitter2 {
5456
6706
  this.#gateway.on("RAW", (data) => this.emit("raw" /* Raw */, data));
5457
6707
  this.#gateway.on("error", (error) => this.emit("error" /* Error */, error));
5458
6708
  }
6709
+ #observeMessage(message) {
6710
+ if (!this.channels.has(message.channelId))
6711
+ this.channels.set(message.channelId, message.channel);
6712
+ if (this.#cache.users)
6713
+ this.#merge(this.users, message.author.id, message.author);
6714
+ }
6715
+ #upsertMember(guildId, data) {
6716
+ const member = new GuildMember({ ...data, guild_id: guildId }, this.#resourceContext);
6717
+ if (this.#cache.users)
6718
+ this.#merge(this.users, member.user.id, member.user);
6719
+ if (!this.#cache.members)
6720
+ return member;
6721
+ return this.#merge(this.guilds.members(guildId), member.user.id, member);
6722
+ }
6723
+ #storeVoiceState(guildId, state) {
6724
+ const states = this.guilds.voiceStates(guildId);
6725
+ if (state.channel_id)
6726
+ states.set(state.user_id, state);
6727
+ else
6728
+ states.delete(state.user_id);
6729
+ }
6730
+ #upsertRole(guildId, data) {
6731
+ if (!this.#cache.roles)
6732
+ return new Role(data);
6733
+ return this.#merge(this.guilds.roles(guildId), data.id, new Role(data));
6734
+ }
6735
+ #merge(manager, id, next) {
6736
+ const existing = manager.get(id);
6737
+ if (!existing) {
6738
+ manager.set(id, next);
6739
+ return next;
6740
+ }
6741
+ for (const [key, value] of Object.entries(next))
6742
+ if (value !== undefined)
6743
+ existing[key] = value;
6744
+ return existing;
6745
+ }
6746
+ createCollector(event, options = {}) {
6747
+ const collector = new Collector(options);
6748
+ let order = 0;
6749
+ const listener = (...args) => {
6750
+ const item = args[0];
6751
+ const id = item?.id;
6752
+ const key = options.key?.(item) ?? (typeof id === "string" ? id : String(order++));
6753
+ collector.handle(key, item).catch((error) => this.emit("error" /* Error */, error instanceof Error ? error : new Error(String(error))));
6754
+ };
6755
+ this.on(event, listener);
6756
+ collector.onDispose(() => this.off(event, listener));
6757
+ return collector;
6758
+ }
6759
+ get resourceContext() {
6760
+ return this.#resourceContext;
6761
+ }
6762
+ #memberPermissions(guildId, memberId, roleIds, channelId) {
6763
+ const guild = this.guilds.get(guildId);
6764
+ if (!guild)
6765
+ return null;
6766
+ let channel = channelId ? this.channels.get(channelId) : undefined;
6767
+ if (channelId) {
6768
+ if (channel?.isThread())
6769
+ channel = channel.parentId ? this.channels.get(channel.parentId) : undefined;
6770
+ if (!channel || channel.guildId !== guildId)
6771
+ return null;
6772
+ }
6773
+ return computePermissions({
6774
+ guildId,
6775
+ ownerId: guild.ownerId,
6776
+ memberId,
6777
+ memberRoleIds: [...roleIds],
6778
+ roles: this.guilds.roles(guildId).values(),
6779
+ overwrites: channel?.permissionOverwrites
6780
+ });
6781
+ }
6782
+ permissionsFor(memberId, guildOrChannelId) {
6783
+ let channel = this.channels.get(guildOrChannelId);
6784
+ if (channel?.isThread()) {
6785
+ channel = channel.parentId ? this.channels.get(channel.parentId) : undefined;
6786
+ if (!channel)
6787
+ return null;
6788
+ }
6789
+ const guildId = channel?.guildId ?? guildOrChannelId;
6790
+ const guild = this.guilds.get(guildId);
6791
+ const member = this.guilds.members(guildId).get(memberId);
6792
+ if (!guild || !member)
6793
+ return null;
6794
+ return computePermissions({
6795
+ guildId,
6796
+ ownerId: guild.ownerId,
6797
+ memberId,
6798
+ memberRoleIds: member.roleIds,
6799
+ roles: this.guilds.roles(guildId).values(),
6800
+ overwrites: channel?.permissionOverwrites
6801
+ });
6802
+ }
6803
+ fetchDefaultSoundboardSounds() {
6804
+ return this.rest.get(Routes.soundboardDefaultSounds());
6805
+ }
5459
6806
  async login(token) {
5460
6807
  if (this.state === "destroyed")
5461
6808
  throw new Error("Cannot login a destroyed client.");
@@ -5475,12 +6822,21 @@ class Client extends EventEmitter2 {
5475
6822
  this.#gateway.close();
5476
6823
  }
5477
6824
  postInteractionResponse(id, token, response) {
5478
- return this.rest.post(Routes.interactionCallback(id, token), response.toJSON());
6825
+ const json = response.toJSON();
6826
+ const upload = json.data ? toRequest(json.data) : undefined;
6827
+ if (upload && typeof upload === "object" && "files" in upload) {
6828
+ const { body, files } = upload;
6829
+ return this.rest.post(Routes.interactionCallback(id, token), {
6830
+ body: { ...json, data: body },
6831
+ files
6832
+ });
6833
+ }
6834
+ return this.rest.post(Routes.interactionCallback(id, token), json);
5479
6835
  }
5480
6836
  editInteractionReply(token, data) {
5481
6837
  if (!this.user)
5482
6838
  return Promise.reject(new Error("Client is unauthenticated."));
5483
- return this.rest.patch(Routes.interactionOriginalResponse(this.user.id, token), data);
6839
+ return this.rest.patch(Routes.interactionOriginalResponse(this.user.id, token), toRequest(data));
5484
6840
  }
5485
6841
  deleteInteractionReply(token) {
5486
6842
  if (!this.user)
@@ -5490,7 +6846,15 @@ class Client extends EventEmitter2 {
5490
6846
  followUpInteraction(token, data) {
5491
6847
  if (!this.user)
5492
6848
  return Promise.reject(new Error("Client is unauthenticated."));
5493
- return this.rest.post(`/webhooks/${this.user.id}/${token}`, data);
6849
+ return this.rest.post(`/webhooks/${this.user.id}/${token}`, toRequest(data));
6850
+ }
6851
+ interactionWebhookMessage(method, applicationId, token, messageId, data) {
6852
+ const path = messageId === "@original" ? Routes.interactionOriginalResponse(applicationId, token) : Routes.webhookMessage(applicationId, token, messageId);
6853
+ if (method === "GET")
6854
+ return this.rest.get(path);
6855
+ if (method === "PATCH")
6856
+ return this.rest.patch(path, data);
6857
+ return this.rest.delete(path);
5494
6858
  }
5495
6859
  fetchWebhook(id, token) {
5496
6860
  return this.rest.get(token ? `/webhooks/${id}/${token}` : `/webhooks/${id}`);
@@ -5647,6 +7011,21 @@ class HandlerRegistry {
5647
7011
  return this.dispatch(event, ...args);
5648
7012
  }
5649
7013
  }
7014
+ // packages/sharding/package.json
7015
+ var package_default2 = {
7016
+ name: "@lunibee/sharding",
7017
+ version: "0.2.1",
7018
+ type: "module",
7019
+ module: "./src/index.ts",
7020
+ types: "./src/index.ts",
7021
+ exports: {
7022
+ ".": "./src/index.ts"
7023
+ },
7024
+ dependencies: {
7025
+ "@lunibee/ws": "workspace:*"
7026
+ }
7027
+ };
7028
+
5650
7029
  // packages/sharding/src/bus.ts
5651
7030
  var REPLY_TYPE = "__lunibee:reply";
5652
7031
 
@@ -5824,7 +7203,7 @@ class ClusterManager {
5824
7203
  const response = await fetch("https://discord.com/api/v10/gateway/bot", {
5825
7204
  headers: {
5826
7205
  Authorization: `Bot ${this.#options.token}`,
5827
- "User-Agent": "Lunibee/0.1.0"
7206
+ "User-Agent": `Lunibee/${package_default2.version}`
5828
7207
  }
5829
7208
  });
5830
7209
  if (!response.ok) {
@@ -5975,6 +7354,34 @@ class ClusterManager {
5975
7354
 
5976
7355
  // packages/sharding/src/index.ts
5977
7356
  var sleep3 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
7357
+ function needsConnection(gateway) {
7358
+ return gateway.state === "CONNECT" /* Connect */ || gateway.state === "RECONNECT" /* Reconnect */ || gateway.state === "CLOSED" /* Closed */;
7359
+ }
7360
+ var HANDSHAKE_SENT = new Set([
7361
+ "IDENTIFY" /* Identify */,
7362
+ "RESUME" /* Resume */,
7363
+ "READY" /* Ready */,
7364
+ "DISPATCH" /* Dispatch */,
7365
+ "HEARTBEAT" /* Heartbeat */,
7366
+ "CLOSED" /* Closed */
7367
+ ]);
7368
+ function handshakeSent(gateway, timeout) {
7369
+ if (HANDSHAKE_SENT.has(gateway.state))
7370
+ return Promise.resolve();
7371
+ return new Promise((resolve) => {
7372
+ const done = () => {
7373
+ clearTimeout(timer);
7374
+ gateway.off("stateChange", onState);
7375
+ resolve();
7376
+ };
7377
+ const onState = (change) => {
7378
+ if (HANDSHAKE_SENT.has(change.next))
7379
+ done();
7380
+ };
7381
+ const timer = setTimeout(done, timeout);
7382
+ gateway.on("stateChange", onState);
7383
+ });
7384
+ }
5978
7385
 
5979
7386
  class ShardManager {
5980
7387
  static IDENTIFY_INTERVAL = 5000;
@@ -5987,6 +7394,7 @@ class ShardManager {
5987
7394
  #destroyed = false;
5988
7395
  #auto;
5989
7396
  #autoScaleTimer;
7397
+ #gatewayInfo;
5990
7398
  constructor(options) {
5991
7399
  if (!options.token?.trim())
5992
7400
  throw new TypeError("A Discord bot token is required.");
@@ -5999,6 +7407,10 @@ class ShardManager {
5999
7407
  throw new RangeError("autoScaleInterval must be an integer of at least 1000 milliseconds.");
6000
7408
  if (options.spawnDelay !== undefined && (!Number.isFinite(options.spawnDelay) || options.spawnDelay < 0))
6001
7409
  throw new RangeError("spawnDelay must be a non-negative finite number of milliseconds.");
7410
+ if (options.maxConcurrency !== undefined && (!Number.isInteger(options.maxConcurrency) || options.maxConcurrency < 1))
7411
+ throw new RangeError("maxConcurrency must be a positive integer.");
7412
+ if (options.handshakeTimeout !== undefined && (!Number.isFinite(options.handshakeTimeout) || options.handshakeTimeout < 0))
7413
+ throw new RangeError("handshakeTimeout must be a non-negative number of milliseconds.");
6002
7414
  this.#auto = options.shardCount === "auto";
6003
7415
  this.#options = {
6004
7416
  spawnDelay: ShardManager.IDENTIFY_INTERVAL,
@@ -6008,10 +7420,13 @@ class ShardManager {
6008
7420
  this.#initialize(count);
6009
7421
  }
6010
7422
  async fetchRecommendedShardCount() {
7423
+ return (await this.fetchGatewayInfo()).shards;
7424
+ }
7425
+ async fetchGatewayInfo() {
6011
7426
  const response = await fetch("https://discord.com/api/v10/gateway/bot", {
6012
7427
  headers: {
6013
7428
  Authorization: `Bot ${this.#options.token}`,
6014
- "User-Agent": "Lunibee/0.1.0"
7429
+ "User-Agent": `Lunibee/${package_default2.version}`
6015
7430
  }
6016
7431
  });
6017
7432
  if (!response.ok)
@@ -6019,7 +7434,17 @@ class ShardManager {
6019
7434
  const data = await response.json();
6020
7435
  if (typeof data.shards !== "number" || !Number.isInteger(data.shards) || data.shards < 1)
6021
7436
  throw new Error("Gateway discovery returned an invalid shard count.");
6022
- return data.shards;
7437
+ const limit = data.session_start_limit;
7438
+ const info = { shards: data.shards };
7439
+ if (limit && typeof limit.total === "number" && typeof limit.remaining === "number" && typeof limit.reset_after === "number" && typeof limit.max_concurrency === "number")
7440
+ info.sessionStartLimit = {
7441
+ total: limit.total,
7442
+ remaining: limit.remaining,
7443
+ resetAfter: limit.reset_after,
7444
+ maxConcurrency: Math.max(1, limit.max_concurrency)
7445
+ };
7446
+ this.#gatewayInfo = info;
7447
+ return info;
6023
7448
  }
6024
7449
  async connect() {
6025
7450
  if (this.#autoScaleTimer) {
@@ -6027,17 +7452,25 @@ class ShardManager {
6027
7452
  this.#autoScaleTimer = undefined;
6028
7453
  }
6029
7454
  await this.#ensureInitialized();
6030
- for (const [id, shard] of this.shards) {
6031
- try {
6032
- await shard.connect();
6033
- } catch (error) {
7455
+ const limit = this.#gatewayInfo?.sessionStartLimit;
7456
+ const ids = [...this.shards].filter(([, gateway]) => needsConnection(gateway)).map(([id]) => id);
7457
+ if (limit && limit.remaining < ids.length)
7458
+ throw new Error(`Session start limit exhausted: ${limit.remaining} of ${limit.total} IDENTIFYs left for ${ids.length} shards; resets in ${Math.ceil(limit.resetAfter / 1000)}s.`);
7459
+ const concurrency = Math.min(this.#options.maxConcurrency ?? limit?.maxConcurrency ?? 1, limit?.maxConcurrency ?? Infinity);
7460
+ for (let start = 0;start < ids.length; start += concurrency) {
7461
+ const round = ids.slice(start, start + concurrency);
7462
+ const results = await Promise.allSettled(round.map((id) => this.shards.get(id).connect()));
7463
+ const failed = results.findIndex((result) => result.status === "rejected");
7464
+ if (failed !== -1) {
6034
7465
  this.destroy();
6035
- throw new Error(`Failed to connect shard ${id}.`, {
6036
- cause: error
7466
+ throw new Error(`Failed to connect shard ${round[failed]}.`, {
7467
+ cause: results[failed].reason
6037
7468
  });
6038
7469
  }
6039
- if (id + 1 < this.shardCount && this.#options.spawnDelay && this.#options.spawnDelay > 0)
7470
+ if (start + concurrency < ids.length && this.#options.spawnDelay && this.#options.spawnDelay > 0) {
7471
+ await Promise.all(round.map((id) => handshakeSent(this.shards.get(id), this.#options.handshakeTimeout ?? 15000)));
6040
7472
  await sleep3(this.#options.spawnDelay);
7473
+ }
6041
7474
  }
6042
7475
  if (this.#options.autoScaleInterval && !this.#autoScaleTimer) {
6043
7476
  this.#autoScaleTimer = setInterval(() => {
@@ -6080,6 +7513,13 @@ class ShardManager {
6080
7513
  get(id) {
6081
7514
  return this.shards.get(id);
6082
7515
  }
7516
+ health() {
7517
+ return [...this.shards].map(([id, gateway]) => ({
7518
+ id,
7519
+ state: gateway.state,
7520
+ ping: gateway.ping
7521
+ }));
7522
+ }
6083
7523
  values() {
6084
7524
  return [...this.shards].map(([id, gateway]) => ({ id, gateway }));
6085
7525
  }
@@ -6108,6 +7548,187 @@ class ShardManager {
6108
7548
  });
6109
7549
  }
6110
7550
  }
7551
+ // packages/utils/src/args.ts
7552
+ var SNOWFLAKE = /^\d{16,22}$/;
7553
+ var TRUE_WORDS = new Set([
7554
+ "true",
7555
+ "yes",
7556
+ "y",
7557
+ "on",
7558
+ "1",
7559
+ "enable",
7560
+ "enabled"
7561
+ ]);
7562
+ var FALSE_WORDS = new Set([
7563
+ "false",
7564
+ "no",
7565
+ "n",
7566
+ "off",
7567
+ "0",
7568
+ "disable",
7569
+ "disabled"
7570
+ ]);
7571
+ function tokenizeArgs(input) {
7572
+ const args = [];
7573
+ let current = "";
7574
+ let quote = null;
7575
+ let started = false;
7576
+ for (let index = 0;index < input.length; index++) {
7577
+ const character = input[index];
7578
+ if (character === "\\" && index + 1 < input.length) {
7579
+ current += input[++index];
7580
+ started = true;
7581
+ } else if (quote) {
7582
+ if (character === quote)
7583
+ quote = null;
7584
+ else
7585
+ current += character;
7586
+ } else if (character === '"' || character === "'") {
7587
+ if (started)
7588
+ current += character;
7589
+ else {
7590
+ quote = character;
7591
+ started = true;
7592
+ }
7593
+ } else if (/\s/.test(character)) {
7594
+ if (started)
7595
+ args.push(current);
7596
+ current = "";
7597
+ started = false;
7598
+ } else {
7599
+ current += character;
7600
+ started = true;
7601
+ }
7602
+ }
7603
+ if (started)
7604
+ args.push(current);
7605
+ return args;
7606
+ }
7607
+ function parseUserMention(value) {
7608
+ const id = /^<@!?(\d{16,22})>$/.exec(value)?.[1] ?? value;
7609
+ return SNOWFLAKE.test(id) ? id : null;
7610
+ }
7611
+ function parseRoleMention(value) {
7612
+ const id = /^<@&(\d{16,22})>$/.exec(value)?.[1] ?? value;
7613
+ return SNOWFLAKE.test(id) ? id : null;
7614
+ }
7615
+ function parseChannelMention(value) {
7616
+ const id = /^<#(\d{16,22})>$/.exec(value)?.[1] ?? value;
7617
+ return SNOWFLAKE.test(id) ? id : null;
7618
+ }
7619
+ function parseMentionable(value) {
7620
+ const role = /^<@&(\d{16,22})>$/.exec(value)?.[1];
7621
+ if (role)
7622
+ return { id: role, type: "role" };
7623
+ const user = parseUserMention(value);
7624
+ return user ? { id: user, type: "user" } : null;
7625
+ }
7626
+ function readOne(spec, raw) {
7627
+ switch (spec.type) {
7628
+ case "string":
7629
+ case "rest":
7630
+ if (spec.maxLength !== undefined && raw.length > spec.maxLength)
7631
+ return {
7632
+ error: `must be at most ${spec.maxLength} characters`
7633
+ };
7634
+ if (spec.choices && !spec.choices.some((choice) => String(choice).toLowerCase() === raw.toLowerCase()))
7635
+ return { error: `must be one of: ${spec.choices.join(", ")}` };
7636
+ return { value: raw };
7637
+ case "integer":
7638
+ case "number": {
7639
+ const value = Number(raw);
7640
+ if (!Number.isFinite(value) || raw.trim() === "")
7641
+ return { error: "must be a number" };
7642
+ if (spec.type === "integer" && !Number.isSafeInteger(value))
7643
+ return { error: "must be a whole number" };
7644
+ if (spec.min !== undefined && value < spec.min)
7645
+ return { error: `must be at least ${spec.min}` };
7646
+ if (spec.max !== undefined && value > spec.max)
7647
+ return { error: `must be at most ${spec.max}` };
7648
+ if (spec.choices && !spec.choices.includes(value))
7649
+ return { error: `must be one of: ${spec.choices.join(", ")}` };
7650
+ return { value };
7651
+ }
7652
+ case "boolean": {
7653
+ const word = raw.toLowerCase();
7654
+ if (TRUE_WORDS.has(word))
7655
+ return { value: true };
7656
+ if (FALSE_WORDS.has(word))
7657
+ return { value: false };
7658
+ return { error: "must be yes or no" };
7659
+ }
7660
+ case "user": {
7661
+ const id = parseUserMention(raw);
7662
+ return id ? { value: id } : { error: "must be a user mention or ID" };
7663
+ }
7664
+ case "role": {
7665
+ const id = parseRoleMention(raw);
7666
+ return id ? { value: id } : { error: "must be a role mention or ID" };
7667
+ }
7668
+ case "channel": {
7669
+ const id = parseChannelMention(raw);
7670
+ return id ? { value: id } : { error: "must be a channel mention or ID" };
7671
+ }
7672
+ case "mentionable": {
7673
+ const value = parseMentionable(raw);
7674
+ return value ? { value } : { error: "must be a user or role mention" };
7675
+ }
7676
+ }
7677
+ }
7678
+ function parsePrefixArgs(input, specs) {
7679
+ const args = typeof input === "string" ? tokenizeArgs(input) : [...input];
7680
+ const values = {};
7681
+ let position = 0;
7682
+ for (const [index, spec] of specs.entries()) {
7683
+ if (spec.type === "rest" && index !== specs.length - 1)
7684
+ throw new TypeError(`The rest argument "${spec.name}" must be the last one.`);
7685
+ const raw = spec.type === "rest" ? args.slice(position).join(" ") : args[position];
7686
+ if (raw === undefined || raw === "") {
7687
+ if (spec.required)
7688
+ return { ok: false, arg: spec.name, error: "is required" };
7689
+ values[spec.name] = undefined;
7690
+ continue;
7691
+ }
7692
+ const read = readOne(spec, raw);
7693
+ if ("error" in read)
7694
+ return { ok: false, arg: spec.name, error: read.error };
7695
+ values[spec.name] = read.value;
7696
+ position += spec.type === "rest" ? args.length : 1;
7697
+ }
7698
+ return { ok: true, values };
7699
+ }
7700
+ var OPTION_TYPES = {
7701
+ 3: "string",
7702
+ 4: "integer",
7703
+ 5: "boolean",
7704
+ 6: "user",
7705
+ 7: "channel",
7706
+ 8: "role",
7707
+ 9: "mentionable",
7708
+ 10: "number"
7709
+ };
7710
+ function argsFromCommandOptions(options, restLast = false) {
7711
+ const specs = [];
7712
+ for (const option of options) {
7713
+ const type = OPTION_TYPES[option.type];
7714
+ if (!type)
7715
+ continue;
7716
+ specs.push({
7717
+ name: option.name,
7718
+ type,
7719
+ required: option.required,
7720
+ min: option.min_value,
7721
+ max: option.max_value,
7722
+ maxLength: option.max_length,
7723
+ choices: option.choices?.map((choice) => choice.value)
7724
+ });
7725
+ }
7726
+ const last = specs[specs.length - 1];
7727
+ if (restLast && last?.type === "string")
7728
+ last.type = "rest";
7729
+ return specs;
7730
+ }
7731
+
6111
7732
  // packages/utils/src/index.ts
6112
7733
  function sleep4(ms) {
6113
7734
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -6203,12 +7824,14 @@ class VoiceConnection {
6203
7824
  if (this.state === "destroyed" /* Destroyed */)
6204
7825
  return;
6205
7826
  this.#closeTransports();
7827
+ this.receiver.close();
6206
7828
  this.#transition("disconnected" /* Disconnected */);
6207
7829
  }
6208
7830
  destroy() {
6209
7831
  if (this.state === "destroyed" /* Destroyed */)
6210
7832
  return;
6211
7833
  this.#closeTransports();
7834
+ this.receiver.close();
6212
7835
  this.channelId = undefined;
6213
7836
  this.#transition("destroyed" /* Destroyed */);
6214
7837
  this.#listeners.clear();
@@ -6416,6 +8039,8 @@ class VoiceReceiver {
6416
8039
  this.#ssrcMap.set(ssrc, userId);
6417
8040
  }
6418
8041
  subscribe(userId) {
8042
+ if (this.connection.state === "destroyed" /* Destroyed */)
8043
+ throw new VoiceError("Voice connection has been destroyed.");
6419
8044
  let controllerRef;
6420
8045
  const stream = new ReadableStream({
6421
8046
  start: (controller) => {
@@ -6436,6 +8061,16 @@ class VoiceReceiver {
6436
8061
  });
6437
8062
  return new AudioStream(stream, { title: `User ${userId} Audio` });
6438
8063
  }
8064
+ close() {
8065
+ for (const controllers of this.#streams.values())
8066
+ for (const controller of controllers) {
8067
+ try {
8068
+ controller.close();
8069
+ } catch {}
8070
+ }
8071
+ this.#streams.clear();
8072
+ this.#ssrcMap.clear();
8073
+ }
6439
8074
  onPacket(packet) {
6440
8075
  if (packet.length < 12)
6441
8076
  return;
@@ -6516,15 +8151,24 @@ function entersState(target, status, timeoutMs) {
6516
8151
  class EmbedBuilder {
6517
8152
  #data = {};
6518
8153
  setTitle(value) {
6519
- this.#data.title = validate(value, 256, "Embed title");
8154
+ if (value === null)
8155
+ delete this.#data.title;
8156
+ else
8157
+ this.#data.title = validate(value, 256, "Embed title");
6520
8158
  return this;
6521
8159
  }
6522
8160
  setDescription(value) {
6523
- this.#data.description = validate(value, 4096, "Embed description");
8161
+ if (value === null)
8162
+ delete this.#data.description;
8163
+ else
8164
+ this.#data.description = validate(value, 4096, "Embed description");
6524
8165
  return this;
6525
8166
  }
6526
8167
  setURL(value) {
6527
- this.#data.url = url(value, "Embed URL");
8168
+ if (value === null)
8169
+ delete this.#data.url;
8170
+ else
8171
+ this.#data.url = url(value, "Embed URL");
6528
8172
  return this;
6529
8173
  }
6530
8174
  setColor(value) {
@@ -6556,11 +8200,19 @@ class EmbedBuilder {
6556
8200
  return this;
6557
8201
  }
6558
8202
  setThumbnail(value) {
8203
+ if (value === null) {
8204
+ delete this.#data.thumbnail;
8205
+ return this;
8206
+ }
6559
8207
  const valueURL = typeof value === "string" ? value : value.url;
6560
8208
  this.#data.thumbnail = { url: url(valueURL, "Thumbnail URL") };
6561
8209
  return this;
6562
8210
  }
6563
8211
  setImage(value) {
8212
+ if (value === null) {
8213
+ delete this.#data.image;
8214
+ return this;
8215
+ }
6564
8216
  const valueURL = typeof value === "string" ? value : value.url;
6565
8217
  this.#data.image = { url: url(valueURL, "Image URL") };
6566
8218
  return this;
@@ -6663,10 +8315,13 @@ class ActionRowBuilder {
6663
8315
  return this;
6664
8316
  }
6665
8317
  toJSON() {
6666
- return {
6667
- type: ComponentType.ActionRow,
6668
- components: this.#components.map((component) => component.toJSON())
6669
- };
8318
+ const components = this.#components.map((component) => component.toJSON());
8319
+ if (components.length === 0)
8320
+ throw new RangeError("An action row needs at least one component.");
8321
+ const types = components.map((component) => component.type);
8322
+ if (types.some((type) => type !== ComponentType.Button) && components.length > 1)
8323
+ throw new RangeError("A select menu or text input must be alone in its action row.");
8324
+ return { type: ComponentType.ActionRow, components };
6670
8325
  }
6671
8326
  }
6672
8327
 
@@ -6721,6 +8376,12 @@ class StringSelectBuilder {
6721
8376
  return this;
6722
8377
  }
6723
8378
  toJSON() {
8379
+ assertSelect(this.#data);
8380
+ const count = this.#data.options?.length ?? 0;
8381
+ if (count === 0)
8382
+ throw new RangeError("A string select needs at least one option.");
8383
+ if ((this.#data.max_values ?? 1) > count)
8384
+ throw new RangeError("max_values cannot exceed the number of options.");
6724
8385
  return structuredClone(this.#data);
6725
8386
  }
6726
8387
  }
@@ -6731,9 +8392,20 @@ class ButtonBuilder {
6731
8392
  style: ButtonStyle.Secondary
6732
8393
  };
6733
8394
  setStyle(style) {
6734
- this.#data.style = style;
6735
- if (style === ButtonStyle.Link)
6736
- delete this.#data.custom_id;
8395
+ const data = this.#data;
8396
+ data.style = style;
8397
+ if (style === ButtonStyle.Link) {
8398
+ delete data.custom_id;
8399
+ delete data.sku_id;
8400
+ } else if (style === ButtonStyle.Premium) {
8401
+ delete data.custom_id;
8402
+ delete data.url;
8403
+ delete data.label;
8404
+ delete data.emoji;
8405
+ } else {
8406
+ delete data.url;
8407
+ delete data.sku_id;
8408
+ }
6737
8409
  return this;
6738
8410
  }
6739
8411
  setCustomId(value) {
@@ -6758,11 +8430,16 @@ class ButtonBuilder {
6758
8430
  cause: error
6759
8431
  });
6760
8432
  }
6761
- this.#data.style = ButtonStyle.Link;
6762
- delete this.#data.custom_id;
8433
+ this.setStyle(ButtonStyle.Link);
6763
8434
  this.#data.url = url.toString();
6764
8435
  return this;
6765
8436
  }
8437
+ setSKUId(skuId) {
8438
+ validateText(skuId, 20, "Button SKU ID");
8439
+ this.setStyle(ButtonStyle.Premium);
8440
+ this.#data.sku_id = skuId;
8441
+ return this;
8442
+ }
6766
8443
  setEmoji(emoji) {
6767
8444
  this.#data.emoji = typeof emoji === "string" ? { name: emoji } : { ...emoji };
6768
8445
  return this;
@@ -6772,7 +8449,26 @@ class ButtonBuilder {
6772
8449
  return this;
6773
8450
  }
6774
8451
  toJSON() {
6775
- return structuredClone(this.#data);
8452
+ const data = this.#data;
8453
+ if (data.style === ButtonStyle.Link) {
8454
+ if (!data.url)
8455
+ throw new TypeError("Link buttons require a URL.");
8456
+ if (data.custom_id || data.sku_id)
8457
+ throw new TypeError("Link buttons cannot have a custom ID or SKU ID.");
8458
+ } else if (data.style === ButtonStyle.Premium) {
8459
+ if (!data.sku_id)
8460
+ throw new TypeError("Premium buttons require a SKU ID.");
8461
+ if (data.custom_id || data.url || data.label || data.emoji)
8462
+ throw new TypeError("Premium buttons cannot have a custom ID, URL, label or emoji.");
8463
+ } else {
8464
+ if (!data.custom_id)
8465
+ throw new TypeError("Non-link buttons require a custom ID.");
8466
+ if (data.url || data.sku_id)
8467
+ throw new TypeError("Only link buttons have a URL and only premium buttons have a SKU ID.");
8468
+ }
8469
+ if (data.style !== ButtonStyle.Premium && !data.label && !data.emoji)
8470
+ throw new TypeError("Buttons require a label or an emoji.");
8471
+ return structuredClone(data);
6776
8472
  }
6777
8473
  }
6778
8474
 
@@ -6816,6 +8512,7 @@ class EntitySelectBuilder {
6816
8512
  return this;
6817
8513
  }
6818
8514
  toJSON() {
8515
+ assertSelect(this.#data);
6819
8516
  return structuredClone(this.#data);
6820
8517
  }
6821
8518
  }
@@ -6842,11 +8539,18 @@ class ModalBuilder {
6842
8539
  this.#components.push(...components);
6843
8540
  return this;
6844
8541
  }
8542
+ addTextInputs(...inputs) {
8543
+ return this.addComponents(...inputs.map((input) => new ActionRowBuilder().addComponents(input)));
8544
+ }
6845
8545
  toJSON() {
8546
+ if (!this.#custom_id || !this.#title)
8547
+ throw new TypeError("Modals require a custom ID and a title.");
8548
+ if (this.#components.length === 0)
8549
+ throw new RangeError("Modals require at least one component.");
6846
8550
  return {
6847
8551
  type: 9,
6848
- ...this.#custom_id ? { custom_id: this.#custom_id } : {},
6849
- ...this.#title ? { title: this.#title } : {},
8552
+ custom_id: this.#custom_id,
8553
+ title: this.#title,
6850
8554
  components: this.#components.map((component) => component.toJSON())
6851
8555
  };
6852
8556
  }
@@ -6896,7 +8600,12 @@ class TextInputBuilder {
6896
8600
  return this;
6897
8601
  }
6898
8602
  toJSON() {
6899
- return structuredClone(this.#data);
8603
+ const data = this.#data;
8604
+ if (!data.custom_id)
8605
+ throw new TypeError("Text inputs require a custom ID.");
8606
+ if (data.min_length !== undefined && data.max_length !== undefined && data.min_length > data.max_length)
8607
+ throw new RangeError("min_length cannot exceed max_length.");
8608
+ return structuredClone(data);
6900
8609
  }
6901
8610
  }
6902
8611
 
@@ -7123,6 +8832,23 @@ class ChannelSelectMenuBuilder extends EntitySelectBuilder {
7123
8832
  super(ComponentType.ChannelSelect);
7124
8833
  }
7125
8834
  }
8835
+ function assertSelect(data) {
8836
+ if (!data.custom_id)
8837
+ throw new TypeError("Select menus require a custom ID.");
8838
+ if ((data.min_values ?? 1) > (data.max_values ?? 1))
8839
+ throw new RangeError("min_values cannot exceed max_values.");
8840
+ }
8841
+ var IS_COMPONENTS_V2 = 1 << 15;
8842
+ function componentsV2Message(components, options) {
8843
+ const list = Array.isArray(components) ? components : [components];
8844
+ if (!list.length)
8845
+ throw new TypeError("A Components V2 message needs at least one component.");
8846
+ return {
8847
+ ...options ?? {},
8848
+ components: list.map((component) => component.toJSON()),
8849
+ flags: (options?.flags ?? 0) | IS_COMPONENTS_V2
8850
+ };
8851
+ }
7126
8852
  // packages/builders/src/commands.ts
7127
8853
  var ApplicationCommandOptionType2 = {
7128
8854
  Subcommand: 1,
@@ -7637,6 +9363,8 @@ export {
7637
9363
  GuildMemberManager,
7638
9364
  GuildOnboarding,
7639
9365
  GuildScheduledEventManager,
9366
+ GuildSoundboardManager,
9367
+ GuildStickerManager,
7640
9368
  GuildWelcomeScreen,
7641
9369
  HandlerRegistry,
7642
9370
  HttpTransport,
@@ -7662,6 +9390,7 @@ export {
7662
9390
  MessageManager,
7663
9391
  ModalBuilder,
7664
9392
  ModalSubmitInteraction,
9393
+ MonetizationManager,
7665
9394
  NewsChannel,
7666
9395
  NumberOptionBuilder,
7667
9396
  OnboardingPrompt,
@@ -7731,6 +9460,7 @@ export {
7731
9460
  WelcomeScreenChannel,
7732
9461
  ZlibStreamDecoder,
7733
9462
  abortError,
9463
+ argsFromCommandOptions,
7734
9464
  blockQuote,
7735
9465
  bold,
7736
9466
  bulletList,
@@ -7739,6 +9469,8 @@ export {
7739
9469
  classifyFrame,
7740
9470
  classifyPayload,
7741
9471
  codeBlock,
9472
+ componentsV2Message,
9473
+ computePermissions,
7742
9474
  createAudioPlayer,
7743
9475
  createAudioResource,
7744
9476
  createChannel,
@@ -7761,7 +9493,13 @@ export {
7761
9493
  masked,
7762
9494
  normalizeRoutePath,
7763
9495
  orderedList,
9496
+ parseChannelMention,
9497
+ parseMentionable,
9498
+ parsePrefixArgs,
9499
+ parseRoleMention,
9500
+ parseUserMention,
7764
9501
  randomInt,
9502
+ redactPath,
7765
9503
  resolveGatewayIntents,
7766
9504
  resumePayload,
7767
9505
  roleMention,
@@ -7772,8 +9510,10 @@ export {
7772
9510
  strikethrough,
7773
9511
  subtext,
7774
9512
  timestamp,
9513
+ toRequest,
9514
+ tokenizeArgs,
7775
9515
  underline,
7776
9516
  userMention
7777
9517
  };
7778
9518
 
7779
- //# debugId=58F0E8EFC21C568E64756E2164756E21
9519
+ //# debugId=9E598E337B852A0164756E2164756E21