lunibee 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +2 -0
  2. package/dist/builders/components.d.ts +5 -0
  3. package/dist/builders/index.js +72 -12
  4. package/dist/builders/index.js.map +5 -5
  5. package/dist/collection/index.d.ts +68 -1
  6. package/dist/collection/index.js +334 -1
  7. package/dist/collection/index.js.map +3 -3
  8. package/dist/core/collector.d.ts +13 -0
  9. package/dist/core/events.d.ts +29 -3
  10. package/dist/core/index.d.ts +22 -8
  11. package/dist/core/index.js +1526 -124
  12. package/dist/core/index.js.map +26 -22
  13. package/dist/core/permissions.d.ts +48 -0
  14. package/dist/index.js +1578 -268
  15. package/dist/index.js.map +30 -29
  16. package/dist/managers/advanced.d.ts +116 -0
  17. package/dist/managers/base.d.ts +13 -2
  18. package/dist/managers/emoji.d.ts +1 -1
  19. package/dist/managers/guild.d.ts +28 -2
  20. package/dist/managers/index.d.ts +37 -5
  21. package/dist/managers/index.js +870 -152
  22. package/dist/managers/index.js.map +18 -16
  23. package/dist/managers/message.d.ts +10 -1
  24. package/dist/rest/errors.d.ts +33 -0
  25. package/dist/rest/index.d.ts +1 -1
  26. package/dist/rest/index.js +52 -6
  27. package/dist/rest/index.js.map +5 -5
  28. package/dist/rest/routes.d.ts +20 -0
  29. package/dist/sharding/index.d.ts +29 -0
  30. package/dist/sharding/index.js +99 -15
  31. package/dist/sharding/index.js.map +8 -8
  32. package/dist/structures/base.d.ts +2 -0
  33. package/dist/structures/index.js +96 -42
  34. package/dist/structures/index.js.map +10 -9
  35. package/dist/structures/interactions.d.ts +26 -0
  36. package/dist/types/gateway.d.ts +16 -0
  37. package/dist/types/index.d.ts +55 -1
  38. package/dist/types/index.js.map +2 -2
  39. package/dist/voice/index.d.ts +3 -0
  40. package/dist/voice/index.js +15 -1
  41. package/dist/voice/index.js.map +3 -3
  42. package/dist/ws/index.js +13 -5
  43. package/dist/ws/index.js.map +6 -6
  44. 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++) {
@@ -419,6 +432,35 @@ class PermissionsBitField extends PermissionSet {
419
432
  super(value);
420
433
  }
421
434
  }
435
+ var ALL_PERMISSIONS = Object.values(Permission).reduce((bits, bit) => bits | bit, 0n);
436
+ var bits = (value) => new PermissionSet(value).bitfield;
437
+ function computePermissions(context) {
438
+ if (context.ownerId !== undefined && context.ownerId === context.memberId)
439
+ return new PermissionSet(ALL_PERMISSIONS);
440
+ const roles = new Map(context.roles.map((role) => [role.id, role]));
441
+ let base = bits(roles.get(context.guildId)?.permissions ?? 0n);
442
+ for (const id of context.memberRoleIds)
443
+ base |= bits(roles.get(id)?.permissions ?? 0n);
444
+ if (base & Permission.administrator)
445
+ return new PermissionSet(ALL_PERMISSIONS);
446
+ const overwrites = context.overwrites ?? [];
447
+ const everyone = overwrites.find((o) => o.id === context.guildId);
448
+ if (everyone)
449
+ base = base & ~bits(everyone.deny) | bits(everyone.allow);
450
+ const memberRoles = new Set(context.memberRoleIds);
451
+ let allow = 0n;
452
+ let deny = 0n;
453
+ for (const overwrite of overwrites)
454
+ if (overwrite.type === 0 /* Role */ && overwrite.id !== context.guildId && memberRoles.has(overwrite.id)) {
455
+ allow |= bits(overwrite.allow);
456
+ deny |= bits(overwrite.deny);
457
+ }
458
+ base = base & ~deny | allow;
459
+ const member = overwrites.find((o) => o.type === 1 /* Member */ && o.id === context.memberId);
460
+ if (member)
461
+ base = base & ~bits(member.deny) | bits(member.allow);
462
+ return new PermissionSet(base);
463
+ }
422
464
  // packages/core/src/events.ts
423
465
  var ClientEvent;
424
466
  ((ClientEvent) => {
@@ -455,6 +497,13 @@ var ClientEvent;
455
497
  ClientEvent["GuildRoleDelete"] = "guildRoleDelete";
456
498
  ClientEvent["GuildEmojisUpdate"] = "guildEmojisUpdate";
457
499
  ClientEvent["GuildStickersUpdate"] = "guildStickersUpdate";
500
+ ClientEvent["EntitlementCreate"] = "entitlementCreate";
501
+ ClientEvent["EntitlementUpdate"] = "entitlementUpdate";
502
+ ClientEvent["EntitlementDelete"] = "entitlementDelete";
503
+ ClientEvent["SoundboardSoundCreate"] = "soundboardSoundCreate";
504
+ ClientEvent["SoundboardSoundUpdate"] = "soundboardSoundUpdate";
505
+ ClientEvent["SoundboardSoundDelete"] = "soundboardSoundDelete";
506
+ ClientEvent["SoundboardSoundsUpdate"] = "soundboardSoundsUpdate";
458
507
  ClientEvent["GuildIntegrationsUpdate"] = "guildIntegrationsUpdate";
459
508
  ClientEvent["GuildScheduledEventCreate"] = "guildScheduledEventCreate";
460
509
  ClientEvent["GuildScheduledEventUpdate"] = "guildScheduledEventUpdate";
@@ -497,6 +546,9 @@ class Collector extends EventEmitter {
497
546
  endReason;
498
547
  totalProcessed = 0;
499
548
  #timeoutTimer;
549
+ #idleTimer;
550
+ #onAbort = () => this.stop("abort");
551
+ #cleanup = [];
500
552
  constructor(options = {}) {
501
553
  super();
502
554
  this.options = options;
@@ -505,6 +557,27 @@ class Collector extends EventEmitter {
505
557
  this.stop("time");
506
558
  }, options.time);
507
559
  }
560
+ this.#resetIdle();
561
+ if (options.signal?.aborted)
562
+ this.stop("abort");
563
+ else
564
+ options.signal?.addEventListener("abort", this.#onAbort, {
565
+ once: true
566
+ });
567
+ }
568
+ onDispose(cleanup) {
569
+ if (this.ended)
570
+ cleanup();
571
+ else
572
+ this.#cleanup.push(cleanup);
573
+ return this;
574
+ }
575
+ #resetIdle() {
576
+ if (!this.options.idle || this.options.idle <= 0)
577
+ return;
578
+ if (this.#idleTimer)
579
+ clearTimeout(this.#idleTimer);
580
+ this.#idleTimer = setTimeout(() => this.stop("idle"), this.options.idle);
508
581
  }
509
582
  async handle(key, item) {
510
583
  if (this.ended)
@@ -522,6 +595,7 @@ class Collector extends EventEmitter {
522
595
  return false;
523
596
  }
524
597
  this.collected.set(key, item);
598
+ this.#resetIdle();
525
599
  this.emit("collect", item);
526
600
  if (this.options.max && this.collected.size >= this.options.max) {
527
601
  this.stop("limit");
@@ -540,9 +614,53 @@ class Collector extends EventEmitter {
540
614
  this.endReason = reason;
541
615
  if (this.#timeoutTimer)
542
616
  clearTimeout(this.#timeoutTimer);
617
+ if (this.#idleTimer)
618
+ clearTimeout(this.#idleTimer);
619
+ this.options.signal?.removeEventListener("abort", this.#onAbort);
620
+ for (const cleanup of this.#cleanup.splice(0)) {
621
+ try {
622
+ cleanup();
623
+ } catch {}
624
+ }
543
625
  this.emit("end", this.collected, reason);
544
626
  this.removeAllListeners();
545
627
  }
628
+ wait() {
629
+ if (this.ended)
630
+ return Promise.resolve(this.collected);
631
+ return new Promise((resolve) => this.once("end", (collected) => resolve(collected)));
632
+ }
633
+ async* [Symbol.asyncIterator]() {
634
+ const queue = [];
635
+ let wake;
636
+ const onCollect = (item) => {
637
+ queue.push(item);
638
+ wake?.();
639
+ };
640
+ const onEnd = () => wake?.();
641
+ if (!this.ended) {
642
+ this.on("collect", onCollect);
643
+ this.on("end", onEnd);
644
+ }
645
+ try {
646
+ for (;; ) {
647
+ if (queue.length > 0) {
648
+ yield queue.shift();
649
+ continue;
650
+ }
651
+ if (this.ended)
652
+ return;
653
+ await new Promise((resolve) => wake = resolve);
654
+ wake = undefined;
655
+ }
656
+ } finally {
657
+ this.off("collect", onCollect);
658
+ this.off("end", onEnd);
659
+ }
660
+ }
661
+ [Symbol.dispose]() {
662
+ this.stop("disposed");
663
+ }
546
664
  next() {
547
665
  return new Promise((resolve, reject) => {
548
666
  if (this.ended) {
@@ -858,7 +976,340 @@ class Cache {
858
976
  }
859
977
 
860
978
  // packages/collection/src/index.ts
979
+ class RecencyList {
980
+ #nodes = new Map;
981
+ #oldest;
982
+ #newest;
983
+ get size() {
984
+ return this.#nodes.size;
985
+ }
986
+ oldest() {
987
+ return this.#oldest?.key;
988
+ }
989
+ touch(key) {
990
+ const node = this.#nodes.get(key);
991
+ if (node)
992
+ return this.#moveNewest(node);
993
+ const created = { key, older: this.#newest };
994
+ if (this.#newest)
995
+ this.#newest.newer = created;
996
+ else
997
+ this.#oldest = created;
998
+ this.#newest = created;
999
+ this.#nodes.set(key, created);
1000
+ }
1001
+ promote(key) {
1002
+ const node = this.#nodes.get(key);
1003
+ if (node)
1004
+ this.#moveNewest(node);
1005
+ }
1006
+ delete(key) {
1007
+ const node = this.#nodes.get(key);
1008
+ if (!node)
1009
+ return false;
1010
+ this.#unlink(node);
1011
+ this.#nodes.delete(key);
1012
+ return true;
1013
+ }
1014
+ clear() {
1015
+ this.#nodes.clear();
1016
+ this.#oldest = this.#newest = undefined;
1017
+ }
1018
+ #unlink(node) {
1019
+ if (node.older)
1020
+ node.older.newer = node.newer;
1021
+ else
1022
+ this.#oldest = node.newer;
1023
+ if (node.newer)
1024
+ node.newer.older = node.older;
1025
+ else
1026
+ this.#newest = node.older;
1027
+ node.older = node.newer = undefined;
1028
+ }
1029
+ #moveNewest(node) {
1030
+ if (node === this.#newest)
1031
+ return;
1032
+ this.#unlink(node);
1033
+ node.older = this.#newest;
1034
+ if (this.#newest)
1035
+ this.#newest.newer = node;
1036
+ else
1037
+ this.#oldest = node;
1038
+ this.#newest = node;
1039
+ }
1040
+ }
1041
+ function assertTTL(ttl) {
1042
+ if (ttl !== undefined && (!Number.isFinite(ttl) || ttl <= 0))
1043
+ throw new RangeError("TTL must be a positive number, or omitted.");
1044
+ }
1045
+
861
1046
  class Collection extends Map {
1047
+ #ttl;
1048
+ #maxSize;
1049
+ #onEvict;
1050
+ #expiry = new Map;
1051
+ #lru = new RecencyList;
1052
+ #stats = {
1053
+ hits: 0,
1054
+ misses: 0,
1055
+ expired: 0,
1056
+ evicted: 0
1057
+ };
1058
+ #heap = [];
1059
+ #timer;
1060
+ #armedFor = Infinity;
1061
+ constructor(entries, options = {}) {
1062
+ super();
1063
+ assertTTL(options.ttl);
1064
+ if (options.maxSize !== undefined && (!Number.isInteger(options.maxSize) || options.maxSize <= 0))
1065
+ throw new RangeError("maxSize must be a positive integer.");
1066
+ this.#ttl = options.ttl;
1067
+ this.#maxSize = options.maxSize;
1068
+ this.#onEvict = options.onEvict;
1069
+ if (entries)
1070
+ for (const [key, value] of entries)
1071
+ this.set(key, value);
1072
+ }
1073
+ set(key, value, ttl) {
1074
+ assertTTL(ttl);
1075
+ const window = ttl ?? this.#ttl;
1076
+ if (this.#maxSize !== undefined) {
1077
+ this.#lru.touch(key);
1078
+ }
1079
+ super.set(key, value);
1080
+ if (window !== undefined)
1081
+ this.#schedule(key, window);
1082
+ else if (this.#expiry.size > 0)
1083
+ this.#expiry.delete(key);
1084
+ this.#enforceCap();
1085
+ return this;
1086
+ }
1087
+ setWithoutTTL(key, value) {
1088
+ if (this.#expiry.size > 0)
1089
+ this.#expiry.delete(key);
1090
+ if (this.#lru.size > 0)
1091
+ this.#lru.delete(key);
1092
+ super.set(key, value);
1093
+ return this;
1094
+ }
1095
+ get(key) {
1096
+ if (this.#expireIfDue(key)) {
1097
+ this.#stats.misses++;
1098
+ return;
1099
+ }
1100
+ const value = super.get(key);
1101
+ if (value === undefined && !super.has(key)) {
1102
+ this.#stats.misses++;
1103
+ return;
1104
+ }
1105
+ this.#stats.hits++;
1106
+ const expiry = this.#expiry.get(key);
1107
+ if (expiry)
1108
+ expiry.deadline = Date.now() + expiry.window;
1109
+ this.#lru.promote(key);
1110
+ return value;
1111
+ }
1112
+ peek(key) {
1113
+ if (!this.#expireIfDue(key) && super.has(key)) {
1114
+ this.#stats.hits++;
1115
+ return super.get(key);
1116
+ }
1117
+ this.#stats.misses++;
1118
+ return;
1119
+ }
1120
+ get stats() {
1121
+ return { ...this.#stats };
1122
+ }
1123
+ has(key) {
1124
+ return !this.#expireIfDue(key) && super.has(key);
1125
+ }
1126
+ delete(key) {
1127
+ if (this.#expireIfDue(key))
1128
+ return false;
1129
+ this.#expiry.delete(key);
1130
+ this.#lru.delete(key);
1131
+ return super.delete(key);
1132
+ }
1133
+ clear() {
1134
+ super.clear();
1135
+ this.#expiry.clear();
1136
+ this.#lru.clear();
1137
+ this.#heap.length = 0;
1138
+ if (this.#timer)
1139
+ clearTimeout(this.#timer);
1140
+ this.#timer = undefined;
1141
+ this.#armedFor = Infinity;
1142
+ }
1143
+ get size() {
1144
+ this.purge();
1145
+ return super.size;
1146
+ }
1147
+ entries() {
1148
+ this.purge();
1149
+ return super.entries();
1150
+ }
1151
+ keys() {
1152
+ this.purge();
1153
+ return super.keys();
1154
+ }
1155
+ values() {
1156
+ this.purge();
1157
+ return super.values();
1158
+ }
1159
+ [Symbol.iterator]() {
1160
+ return this.entries();
1161
+ }
1162
+ forEach(callback, thisArg) {
1163
+ this.purge();
1164
+ super.forEach(callback, thisArg);
1165
+ }
1166
+ ttlRemaining(key) {
1167
+ if (this.#expireIfDue(key))
1168
+ return;
1169
+ const expiry = this.#expiry.get(key);
1170
+ return expiry && Math.max(0, expiry.deadline - Date.now());
1171
+ }
1172
+ purge() {
1173
+ if (this.#expiry.size === 0)
1174
+ return 0;
1175
+ const now = Date.now();
1176
+ let removed = 0;
1177
+ const dropped = [];
1178
+ while (this.#nextDeadline() <= now) {
1179
+ const due = this.#heapPop();
1180
+ dropped.push([due.key, super.get(due.key)]);
1181
+ this.#remove(due.key);
1182
+ removed++;
1183
+ }
1184
+ this.#stats.expired += removed;
1185
+ this.#rearm();
1186
+ for (const [key, value] of dropped)
1187
+ this.#notify(key, value, "expired");
1188
+ return removed;
1189
+ }
1190
+ #expireIfDue(key) {
1191
+ const expiry = this.#expiry.get(key);
1192
+ if (!expiry || expiry.deadline > Date.now())
1193
+ return false;
1194
+ const value = super.get(key);
1195
+ this.#remove(key);
1196
+ this.#stats.expired++;
1197
+ this.#notify(key, value, "expired");
1198
+ return true;
1199
+ }
1200
+ #remove(key) {
1201
+ this.#expiry.delete(key);
1202
+ this.#lru.delete(key);
1203
+ super.delete(key);
1204
+ }
1205
+ #notify(key, value, reason) {
1206
+ if (!this.#onEvict)
1207
+ return;
1208
+ try {
1209
+ this.#onEvict(key, value, reason);
1210
+ } catch {}
1211
+ }
1212
+ #enforceCap() {
1213
+ if (this.#maxSize === undefined)
1214
+ return;
1215
+ while (this.#lru.size > this.#maxSize) {
1216
+ const oldest = this.#lru.oldest();
1217
+ const value = super.get(oldest);
1218
+ this.#remove(oldest);
1219
+ this.#stats.evicted++;
1220
+ this.#notify(oldest, value, "evicted");
1221
+ }
1222
+ }
1223
+ #schedule(key, window) {
1224
+ const deadline = Date.now() + window;
1225
+ const expiry = this.#expiry.get(key);
1226
+ if (expiry) {
1227
+ expiry.deadline = deadline;
1228
+ expiry.window = window;
1229
+ if (deadline >= expiry.filed)
1230
+ return;
1231
+ expiry.filed = deadline;
1232
+ } else
1233
+ this.#expiry.set(key, { deadline, window, filed: deadline });
1234
+ this.#heapPush({ key, deadline });
1235
+ if (this.#heap.length > 2 * this.#expiry.size + 8)
1236
+ this.#compact();
1237
+ this.#rearm();
1238
+ }
1239
+ #nextDeadline() {
1240
+ for (;; ) {
1241
+ const top = this.#heap[0];
1242
+ if (top === undefined)
1243
+ return Infinity;
1244
+ const expiry = this.#expiry.get(top.key);
1245
+ if (!expiry || expiry.filed !== top.deadline) {
1246
+ this.#heapPop();
1247
+ continue;
1248
+ }
1249
+ if (expiry.deadline === top.deadline)
1250
+ return top.deadline;
1251
+ this.#heapPop();
1252
+ expiry.filed = expiry.deadline;
1253
+ this.#heapPush({ key: top.key, deadline: expiry.deadline });
1254
+ }
1255
+ }
1256
+ #compact() {
1257
+ const live = this.#heap.filter((record) => this.#expiry.get(record.key)?.filed === record.deadline);
1258
+ this.#heap.length = 0;
1259
+ for (const record of live)
1260
+ this.#heapPush(record);
1261
+ }
1262
+ #rearm() {
1263
+ const deadline = this.#nextDeadline();
1264
+ if (this.#timer !== undefined && deadline >= this.#armedFor)
1265
+ return;
1266
+ if (this.#timer)
1267
+ clearTimeout(this.#timer);
1268
+ this.#timer = undefined;
1269
+ this.#armedFor = deadline;
1270
+ if (deadline === Infinity)
1271
+ return;
1272
+ this.#timer = setTimeout(() => {
1273
+ this.#timer = undefined;
1274
+ this.#armedFor = Infinity;
1275
+ this.purge();
1276
+ }, Math.max(0, deadline - Date.now()));
1277
+ this.#timer.unref?.();
1278
+ }
1279
+ #heapPush(record) {
1280
+ const heap = this.#heap;
1281
+ heap.push(record);
1282
+ let i = heap.length - 1;
1283
+ while (i > 0) {
1284
+ const parent = i - 1 >> 1;
1285
+ if (heap[parent].deadline <= heap[i].deadline)
1286
+ break;
1287
+ [heap[parent], heap[i]] = [heap[i], heap[parent]];
1288
+ i = parent;
1289
+ }
1290
+ }
1291
+ #heapPop() {
1292
+ const heap = this.#heap;
1293
+ const top = heap[0];
1294
+ const last = heap.pop();
1295
+ if (top === undefined || heap.length === 0)
1296
+ return top;
1297
+ heap[0] = last;
1298
+ for (let i = 0;; ) {
1299
+ const left = 2 * i + 1;
1300
+ const right = left + 1;
1301
+ let smallest = i;
1302
+ if (left < heap.length && heap[left].deadline < heap[smallest].deadline)
1303
+ smallest = left;
1304
+ if (right < heap.length && heap[right].deadline < heap[smallest].deadline)
1305
+ smallest = right;
1306
+ if (smallest === i)
1307
+ break;
1308
+ [heap[smallest], heap[i]] = [heap[i], heap[smallest]];
1309
+ i = smallest;
1310
+ }
1311
+ return top;
1312
+ }
862
1313
  first() {
863
1314
  for (const value of this.values())
864
1315
  return value;
@@ -1083,11 +1534,40 @@ class Manager {
1083
1534
  has(id) {
1084
1535
  return this.cache.has(id);
1085
1536
  }
1537
+ #inflight = new Map;
1538
+ fetchOnce(id, load, store = (value) => {
1539
+ this.set(id, value);
1540
+ return value;
1541
+ }) {
1542
+ const pending = this.#inflight.get(id);
1543
+ if (pending)
1544
+ return pending.promise;
1545
+ const entry = {
1546
+ promise: new Promise((resolve) => resolve(load())),
1547
+ dirty: false
1548
+ };
1549
+ this.#inflight.set(id, entry);
1550
+ entry.promise = entry.promise.then((value) => {
1551
+ this.#inflight.delete(id);
1552
+ return entry.dirty ? this.get(id) ?? value : store(value);
1553
+ }, (error) => {
1554
+ this.#inflight.delete(id);
1555
+ throw error;
1556
+ });
1557
+ return entry.promise;
1558
+ }
1559
+ #markDirty(id) {
1560
+ const pending = this.#inflight.get(id);
1561
+ if (pending)
1562
+ pending.dirty = true;
1563
+ }
1086
1564
  set(id, value) {
1087
- this.cache.set(id, value);
1565
+ this.#markDirty(id);
1566
+ this.cache.setWithoutTTL(id, value);
1088
1567
  return this;
1089
1568
  }
1090
1569
  delete(id) {
1570
+ this.#markDirty(id);
1091
1571
  return this.cache.delete(id);
1092
1572
  }
1093
1573
  clear() {
@@ -1123,16 +1603,20 @@ class ResourceManager extends Manager {
1123
1603
  async resolve(id) {
1124
1604
  return this.get(id) ?? this.fetch(id);
1125
1605
  }
1126
- async fetch(id) {
1127
- const resource = await this.#fetcher(id);
1128
- this.set(id, resource);
1129
- return resource;
1606
+ fetch(id) {
1607
+ return this.fetchOnce(id, () => this.#fetcher(id));
1130
1608
  }
1131
1609
  async fetchMany(ids) {
1132
1610
  return Promise.all([...ids].map((id) => this.resolve(id)));
1133
1611
  }
1134
1612
  upsert(resource) {
1135
1613
  const key = this.#key(resource);
1614
+ const existing = this.get(key);
1615
+ if (existing !== undefined && existing !== resource && typeof existing === "object" && existing !== null) {
1616
+ Object.assign(existing, resource);
1617
+ this.set(key, existing);
1618
+ return existing;
1619
+ }
1136
1620
  this.set(key, resource);
1137
1621
  return resource;
1138
1622
  }
@@ -1143,7 +1627,7 @@ class ResourceManager extends Manager {
1143
1627
  // packages/rest/package.json
1144
1628
  var package_default = {
1145
1629
  name: "@lunibee/rest",
1146
- version: "0.1.8",
1630
+ version: "0.2.0",
1147
1631
  type: "module",
1148
1632
  module: "./src/index.ts",
1149
1633
  types: "./src/index.ts",
@@ -1203,7 +1687,29 @@ class MemoryRateLimitStore {
1203
1687
  }
1204
1688
 
1205
1689
  // packages/rest/src/errors.ts
1690
+ function kindFromStatus(status) {
1691
+ if (status === 429)
1692
+ return "rateLimited";
1693
+ if (status === 401)
1694
+ return "authentication";
1695
+ if (status === 403)
1696
+ return "permission";
1697
+ if (status === 404)
1698
+ return "notFound";
1699
+ if (status === 400 || status === 422)
1700
+ return "validation";
1701
+ if (status >= 500)
1702
+ return "server";
1703
+ if (status === 0)
1704
+ return "network";
1705
+ return "client";
1706
+ }
1707
+ function redactPath(path) {
1708
+ return path.replace(/^(\/webhooks\/[^/?]+\/)[^/?]+/, "$1:token").replace(/^(\/interactions\/[^/?]+\/)[^/?]+/, "$1:token");
1709
+ }
1710
+
1206
1711
  class RESTError extends Error {
1712
+ kind;
1207
1713
  status;
1208
1714
  code;
1209
1715
  errors;
@@ -1213,14 +1719,18 @@ class RESTError extends Error {
1213
1719
  super(message, options.cause === undefined ? undefined : { cause: options.cause });
1214
1720
  this.name = "RESTError";
1215
1721
  this.status = status;
1722
+ this.kind = options.kind ?? kindFromStatus(status);
1216
1723
  this.code = code;
1217
1724
  this.errors = errors;
1218
1725
  this.method = options.method;
1219
- this.path = options.path;
1726
+ this.path = options.path === undefined ? undefined : redactPath(options.path);
1727
+ }
1728
+ get retryable() {
1729
+ return this.kind === "rateLimited" || this.kind === "server" || this.kind === "network" || this.kind === "timeout";
1220
1730
  }
1221
1731
  }
1222
1732
  function abortError(path, reason) {
1223
- return new RESTError(reason instanceof Error ? reason.message : "Discord REST request was aborted", 0, undefined, undefined, { path, cause: reason });
1733
+ return new RESTError(reason instanceof Error ? reason.message : "Discord REST request was aborted", 0, undefined, undefined, { path, cause: reason, kind: "aborted" });
1224
1734
  }
1225
1735
  async function sleep(delay, signal, path) {
1226
1736
  if (delay <= 0)
@@ -1555,8 +2065,23 @@ var Routes = {
1555
2065
  invite: (code) => `/invites/${encodeURIComponent(code)}`,
1556
2066
  guildVanity: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/vanity-url`,
1557
2067
  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`
2068
+ applicationEmoji: (applicationId, emojiId) => emojiId ? `/applications/${snowflake(applicationId, "Application ID")}/emojis/${snowflake(emojiId, "Emoji ID")}` : `/applications/${snowflake(applicationId, "Application ID")}/emojis`,
2069
+ pollExpire: (channelId, messageId) => `/channels/${snowflake(channelId, "Channel ID")}/polls/${snowflake(messageId, "Message ID")}/expire`,
2070
+ pollAnswerVoters: (channelId, messageId, answerId) => `/channels/${snowflake(channelId, "Channel ID")}/polls/${snowflake(messageId, "Message ID")}/answers/${integer(answerId, "Answer ID")}`,
2071
+ guildSticker: (guildId, stickerId) => stickerId ? `/guilds/${snowflake(guildId, "Guild ID")}/stickers/${snowflake(stickerId, "Sticker ID")}` : `/guilds/${snowflake(guildId, "Guild ID")}/stickers`,
2072
+ sendSoundboardSound: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/send-soundboard-sound`,
2073
+ soundboardDefaultSounds: () => "/soundboard-default-sounds",
2074
+ guildSoundboardSound: (guildId, soundId) => soundId ? `/guilds/${snowflake(guildId, "Guild ID")}/soundboard-sounds/${snowflake(soundId, "Sound ID")}` : `/guilds/${snowflake(guildId, "Guild ID")}/soundboard-sounds`,
2075
+ applicationSkus: (applicationId) => `/applications/${snowflake(applicationId, "Application ID")}/skus`,
2076
+ applicationEntitlement: (applicationId, entitlementId) => entitlementId ? `/applications/${snowflake(applicationId, "Application ID")}/entitlements/${snowflake(entitlementId, "Entitlement ID")}` : `/applications/${snowflake(applicationId, "Application ID")}/entitlements`,
2077
+ consumeEntitlement: (applicationId, entitlementId) => `/applications/${snowflake(applicationId, "Application ID")}/entitlements/${snowflake(entitlementId, "Entitlement ID")}/consume`,
2078
+ skuSubscription: (skuId, subscriptionId) => subscriptionId ? `/skus/${snowflake(skuId, "SKU ID")}/subscriptions/${snowflake(subscriptionId, "Subscription ID")}` : `/skus/${snowflake(skuId, "SKU ID")}/subscriptions`
1559
2079
  };
2080
+ function integer(value, field) {
2081
+ if (!Number.isInteger(value) || value < 0)
2082
+ throw new TypeError(`${field} must be a non-negative integer.`);
2083
+ return String(value);
2084
+ }
1560
2085
  function snowflake(value, field) {
1561
2086
  if (!/^\d{1,20}$/.test(value))
1562
2087
  throw new TypeError(`${field} must be a valid Discord snowflake.`);
@@ -1870,7 +2395,8 @@ class REST {
1870
2395
  throw new RESTError(failure.message, 0, undefined, undefined, {
1871
2396
  method,
1872
2397
  path,
1873
- cause: failure.cause ?? failure
2398
+ cause: failure.cause ?? failure,
2399
+ kind: failure.timedOut ? "timeout" : "network"
1874
2400
  });
1875
2401
  }
1876
2402
  this.#emit(this.#hooks.onResponse, {
@@ -1969,6 +2495,9 @@ class REST {
1969
2495
  #emit(hook, ctx) {
1970
2496
  if (!hook)
1971
2497
  return;
2498
+ const withPath = ctx;
2499
+ if (typeof withPath.path === "string")
2500
+ ctx = { ...ctx, path: redactPath(withPath.path) };
1972
2501
  Promise.resolve().then(() => hook(ctx)).catch(() => {});
1973
2502
  }
1974
2503
  }
@@ -2045,6 +2574,7 @@ class Channel extends BaseStructure {
2045
2574
  nsfw;
2046
2575
  rateLimitPerUser;
2047
2576
  position;
2577
+ permissionOverwrites;
2048
2578
  #context;
2049
2579
  constructor(data, context) {
2050
2580
  super(data.id);
@@ -2058,6 +2588,7 @@ class Channel extends BaseStructure {
2058
2588
  this.nsfw = data.nsfw;
2059
2589
  this.rateLimitPerUser = data.rate_limit_per_user;
2060
2590
  this.position = data.position;
2591
+ this.permissionOverwrites = (data.permission_overwrites ?? []).map((overwrite) => ({ ...overwrite }));
2061
2592
  this.#context = context;
2062
2593
  }
2063
2594
  sendMessage(options) {
@@ -2810,6 +3341,17 @@ var InteractionType = {
2810
3341
  ApplicationCommandAutocomplete: 4,
2811
3342
  ModalSubmit: 5
2812
3343
  };
3344
+ var EPHEMERAL = 64;
3345
+ var TOKEN_LIFETIME_MS = 15 * 60000;
3346
+ var DISCORD_EPOCH = 1420070400000n;
3347
+ function toMessageData(options) {
3348
+ if (typeof options === "string")
3349
+ return { content: options };
3350
+ const { ephemeral, ...data } = options;
3351
+ if (ephemeral)
3352
+ data.flags = (typeof data.flags === "number" ? data.flags : 0) | EPHEMERAL;
3353
+ return data;
3354
+ }
2813
3355
 
2814
3356
  class InteractionResponse {
2815
3357
  type;
@@ -2824,14 +3366,10 @@ class InteractionResponse {
2824
3366
  return this.data === undefined ? { type: this.type } : { type: this.type, data: this.data };
2825
3367
  }
2826
3368
  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);
3369
+ return new InteractionResponse(InteractionResponseType.ChannelMessage, toMessageData(options));
2832
3370
  }
2833
3371
  static defer(ephemeral = false) {
2834
- return new InteractionResponse(InteractionResponseType.DeferredChannelMessage, ephemeral ? { flags: 64 } : undefined);
3372
+ return new InteractionResponse(InteractionResponseType.DeferredChannelMessage, ephemeral ? { flags: EPHEMERAL } : undefined);
2835
3373
  }
2836
3374
  static pong() {
2837
3375
  return new InteractionResponse(InteractionResponseType.Pong);
@@ -2849,6 +3387,7 @@ class Interaction {
2849
3387
  replied = false;
2850
3388
  deferred = false;
2851
3389
  #client;
3390
+ #acknowledging = false;
2852
3391
  constructor(client, data) {
2853
3392
  if (!data.id || !data.token)
2854
3393
  throw new TypeError("Interaction ID and token are required.");
@@ -2898,9 +3437,57 @@ class Interaction {
2898
3437
  return [3, 5, 6, 7, 8].includes(this.#componentType());
2899
3438
  }
2900
3439
  assertUnacknowledged() {
2901
- if (this.replied || this.deferred)
3440
+ if (this.replied || this.deferred || this.#acknowledging)
2902
3441
  throw new Error("Interaction has already been acknowledged.");
2903
3442
  }
3443
+ async acknowledge(response, state) {
3444
+ this.assertUnacknowledged();
3445
+ this.#acknowledging = true;
3446
+ try {
3447
+ const result = await this.postResponse(response);
3448
+ this[state] = true;
3449
+ return result;
3450
+ } finally {
3451
+ this.#acknowledging = false;
3452
+ }
3453
+ }
3454
+ get user() {
3455
+ const raw = this.data.member?.user ?? this.data.user;
3456
+ return raw ? new User(raw) : null;
3457
+ }
3458
+ get member() {
3459
+ const raw = this.data.member;
3460
+ if (!raw || !this.guildId)
3461
+ return null;
3462
+ return new GuildMember({
3463
+ ...raw,
3464
+ guild_id: this.guildId
3465
+ });
3466
+ }
3467
+ get createdTimestamp() {
3468
+ return Number((BigInt(this.id) >> 22n) + DISCORD_EPOCH);
3469
+ }
3470
+ get expiresAt() {
3471
+ return new Date(this.createdTimestamp + TOKEN_LIFETIME_MS);
3472
+ }
3473
+ get isExpired() {
3474
+ return Date.now() >= this.createdTimestamp + TOKEN_LIFETIME_MS;
3475
+ }
3476
+ #webhookMessage(method, messageId, data) {
3477
+ if (!this.#client.interactionWebhookMessage)
3478
+ return Promise.reject(new Error("This interaction client does not support webhook message access."));
3479
+ return this.#client.interactionWebhookMessage(method, this.applicationId, this.token, messageId, data);
3480
+ }
3481
+ fetchReply() {
3482
+ this.assertAcknowledged();
3483
+ return this.#webhookMessage("GET", "@original");
3484
+ }
3485
+ editFollowUp(messageId, options) {
3486
+ return this.#webhookMessage("PATCH", messageId, toMessageData(options));
3487
+ }
3488
+ async deleteFollowUp(messageId) {
3489
+ await this.#webhookMessage("DELETE", messageId);
3490
+ }
2904
3491
  assertAcknowledged() {
2905
3492
  if (!this.replied && !this.deferred)
2906
3493
  throw new Error("Interaction has not been acknowledged.");
@@ -2909,41 +3496,27 @@ class Interaction {
2909
3496
  return this.#client.postInteractionResponse(this.id, this.token, response);
2910
3497
  }
2911
3498
  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;
3499
+ return this.acknowledge(InteractionResponse.message(toMessageData(options)), "replied");
2917
3500
  }
2918
3501
  async deferReply(ephemeral = false) {
2919
- this.assertUnacknowledged();
2920
- await this.#client.postInteractionResponse(this.id, this.token, InteractionResponse.defer(ephemeral));
2921
- this.deferred = true;
3502
+ await this.acknowledge(InteractionResponse.defer(ephemeral), "deferred");
2922
3503
  }
2923
3504
  editReply(options) {
2924
3505
  this.assertAcknowledged();
2925
- return this.#client.editInteractionReply(this.token, options);
3506
+ return this.#client.editInteractionReply(this.token, toMessageData(options));
2926
3507
  }
2927
3508
  deleteReply() {
2928
3509
  this.assertAcknowledged();
2929
3510
  return this.#client.deleteInteractionReply(this.token);
2930
3511
  }
2931
3512
  followUp(options) {
2932
- const payload = typeof options === "string" ? { content: options } : options;
2933
- return this.#client.followUpInteraction(this.token, payload);
3513
+ return this.#client.followUpInteraction(this.token, toMessageData(options));
2934
3514
  }
2935
3515
  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;
3516
+ return this.acknowledge(new InteractionResponse(InteractionResponseType.MessageUpdate, toMessageData(options)), "replied");
2941
3517
  }
2942
3518
  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;
3519
+ return this.acknowledge(new InteractionResponse(InteractionResponseType.Modal, modal), "replied");
2947
3520
  }
2948
3521
  }
2949
3522
 
@@ -2971,16 +3544,10 @@ class ComponentInteraction extends Interaction {
2971
3544
  return this.data?.data?.values ?? [];
2972
3545
  }
2973
3546
  async deferUpdate() {
2974
- this.assertUnacknowledged();
2975
- await this.postResponse(new InteractionResponse(InteractionResponseType.DeferredMessageUpdate));
2976
- this.deferred = true;
3547
+ await this.acknowledge(new InteractionResponse(InteractionResponseType.DeferredMessageUpdate), "deferred");
2977
3548
  }
2978
3549
  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;
3550
+ return this.acknowledge(new InteractionResponse(InteractionResponseType.MessageUpdate, toMessageData(options)), "replied");
2984
3551
  }
2985
3552
  }
2986
3553
 
@@ -3023,8 +3590,7 @@ class AutocompleteInteraction extends Interaction {
3023
3590
  if (!Array.isArray(choices))
3024
3591
  throw new TypeError("Autocomplete choices must be an array.");
3025
3592
  const response = new InteractionResponse(InteractionResponseType.Autocomplete, { choices });
3026
- await this.postResponse(response);
3027
- this.replied = true;
3593
+ await this.acknowledge(response, "replied");
3028
3594
  }
3029
3595
  }
3030
3596
  function findFocused(options) {
@@ -3377,16 +3943,22 @@ class Message extends BaseStructure {
3377
3943
 
3378
3944
  // packages/managers/src/message.ts
3379
3945
  class MessageManager {
3380
- cache = new Collection;
3946
+ cache;
3947
+ #caching;
3381
3948
  #rest;
3382
3949
  #context;
3383
3950
  #channelId;
3384
- constructor(rest, context, channelId) {
3951
+ constructor(rest, context, channelId, cache) {
3385
3952
  if (!channelId)
3386
3953
  throw new TypeError("Channel ID is required.");
3387
3954
  this.#rest = rest;
3388
3955
  this.#context = context;
3389
3956
  this.#channelId = channelId;
3957
+ this.#caching = cache !== undefined;
3958
+ this.cache = new Collection(null, {
3959
+ ttl: cache?.ttl,
3960
+ maxSize: cache ? cache.maxSize ?? 100 : undefined
3961
+ });
3390
3962
  }
3391
3963
  async resolve(messageId) {
3392
3964
  return this.cache.get(messageId) ?? this.fetch(messageId);
@@ -3403,13 +3975,14 @@ class MessageManager {
3403
3975
  return Promise.all(Array.from(messageIds, (messageId) => this.fetch(messageId)));
3404
3976
  }
3405
3977
  upsert(data) {
3406
- const existing = this.cache.get(data.id);
3978
+ const existing = this.cache.peek(data.id);
3407
3979
  const message = new Message(data, this.#context);
3408
3980
  if (existing) {
3409
3981
  Object.assign(existing, message);
3410
3982
  return existing;
3411
3983
  }
3412
- this.cache.set(message.id, message);
3984
+ if (this.#caching)
3985
+ this.cache.set(message.id, message);
3413
3986
  return message;
3414
3987
  }
3415
3988
  delete(messageId) {
@@ -3463,8 +4036,295 @@ class UserManager extends ResourceManager {
3463
4036
  });
3464
4037
  }
3465
4038
  }
4039
+ // packages/managers/src/emoji.ts
4040
+ class EmojiManager extends Manager {
4041
+ #rest;
4042
+ #guildId;
4043
+ constructor(rest, guildId) {
4044
+ super();
4045
+ this.#rest = rest;
4046
+ this.#guildId = guildId;
4047
+ }
4048
+ fetch(emojiId) {
4049
+ return this.fetchOnce(emojiId, async () => new Emoji(await this.#rest.get(Routes.guildEmoji(this.#guildId, emojiId))), (emoji) => this.#merge(emojiId, emoji));
4050
+ }
4051
+ async fetchAll() {
4052
+ const data = await this.#rest.get(Routes.guildEmoji(this.#guildId));
4053
+ return data.map((item) => this.upsert(item));
4054
+ }
4055
+ async create(options) {
4056
+ return this.upsert(await this.#rest.post(Routes.guildEmoji(this.#guildId), options));
4057
+ }
4058
+ async edit(emojiId, options) {
4059
+ return this.upsert(await this.#rest.patch(Routes.guildEmoji(this.#guildId, emojiId), options));
4060
+ }
4061
+ async deleteEmoji(emojiId) {
4062
+ await this.#rest.delete(Routes.guildEmoji(this.#guildId, emojiId));
4063
+ this.delete(emojiId);
4064
+ }
4065
+ upsert(data) {
4066
+ const key = data.id != null ? data.id : `unicode:${data.name ?? ""}`;
4067
+ return this.#merge(key, new Emoji(data));
4068
+ }
4069
+ #merge(key, emoji) {
4070
+ const existing = this.get(key);
4071
+ if (existing) {
4072
+ Object.assign(existing, emoji);
4073
+ return existing;
4074
+ }
4075
+ this.set(key, emoji);
4076
+ return emoji;
4077
+ }
4078
+ }
4079
+
4080
+ // packages/managers/src/advanced.ts
4081
+ function withQuery(path, query) {
4082
+ const params = new URLSearchParams;
4083
+ for (const [key, value] of Object.entries(query))
4084
+ if (value !== undefined)
4085
+ params.set(key, String(value));
4086
+ const suffix = params.toString();
4087
+ return suffix ? `${path}?${suffix}` : path;
4088
+ }
4089
+
4090
+ class GuildStickerManager extends Manager {
4091
+ #rest;
4092
+ guildId;
4093
+ constructor(rest, guildId) {
4094
+ super();
4095
+ this.#rest = rest;
4096
+ this.guildId = guildId;
4097
+ }
4098
+ #store(sticker) {
4099
+ this.set(sticker.id, sticker);
4100
+ return sticker;
4101
+ }
4102
+ async fetchAll() {
4103
+ const stickers = await this.#rest.get(Routes.guildSticker(this.guildId));
4104
+ this.clear();
4105
+ return stickers.map((sticker) => this.#store(sticker));
4106
+ }
4107
+ async fetch(stickerId) {
4108
+ return this.#store(await this.#rest.get(Routes.guildSticker(this.guildId, stickerId)));
4109
+ }
4110
+ async create(options) {
4111
+ const form = new FormData;
4112
+ form.set("name", options.name);
4113
+ form.set("description", options.description);
4114
+ form.set("tags", options.tags);
4115
+ form.set("file", options.file);
4116
+ return this.#store(await this.#rest.post(Routes.guildSticker(this.guildId), form, { reason: options.reason }));
4117
+ }
4118
+ async edit(stickerId, options) {
4119
+ const { reason, ...body } = options;
4120
+ return this.#store(await this.#rest.patch(Routes.guildSticker(this.guildId, stickerId), body, { reason }));
4121
+ }
4122
+ async remove(stickerId, reason) {
4123
+ await this.#rest.delete(Routes.guildSticker(this.guildId, stickerId), {
4124
+ reason
4125
+ });
4126
+ this.delete(stickerId);
4127
+ }
4128
+ sync(stickers) {
4129
+ this.clear();
4130
+ for (const sticker of stickers)
4131
+ this.#store(sticker);
4132
+ }
4133
+ }
4134
+
4135
+ class GuildSoundboardManager extends Manager {
4136
+ #rest;
4137
+ guildId;
4138
+ constructor(rest, guildId) {
4139
+ super();
4140
+ this.#rest = rest;
4141
+ this.guildId = guildId;
4142
+ }
4143
+ #store(sound) {
4144
+ this.set(sound.sound_id, sound);
4145
+ return sound;
4146
+ }
4147
+ async fetchAll() {
4148
+ const { items } = await this.#rest.get(Routes.guildSoundboardSound(this.guildId));
4149
+ this.clear();
4150
+ return items.map((sound) => this.#store(sound));
4151
+ }
4152
+ async fetch(soundId) {
4153
+ return this.#store(await this.#rest.get(Routes.guildSoundboardSound(this.guildId, soundId)));
4154
+ }
4155
+ async create(options) {
4156
+ if (options.volume !== undefined && (options.volume < 0 || options.volume > 1))
4157
+ throw new RangeError("Soundboard volume must be between 0 and 1.");
4158
+ return this.#store(await this.#rest.post(Routes.guildSoundboardSound(this.guildId), {
4159
+ name: options.name,
4160
+ sound: options.sound,
4161
+ volume: options.volume,
4162
+ emoji_id: options.emojiId,
4163
+ emoji_name: options.emojiName
4164
+ }, { reason: options.reason }));
4165
+ }
4166
+ async edit(soundId, options) {
4167
+ return this.#store(await this.#rest.patch(Routes.guildSoundboardSound(this.guildId, soundId), {
4168
+ name: options.name,
4169
+ volume: options.volume,
4170
+ emoji_id: options.emojiId,
4171
+ emoji_name: options.emojiName
4172
+ }, { reason: options.reason }));
4173
+ }
4174
+ async remove(soundId, reason) {
4175
+ await this.#rest.delete(Routes.guildSoundboardSound(this.guildId, soundId), { reason });
4176
+ this.delete(soundId);
4177
+ }
4178
+ }
4179
+
4180
+ class MonetizationManager extends Manager {
4181
+ #rest;
4182
+ applicationId;
4183
+ constructor(rest, applicationId) {
4184
+ super();
4185
+ this.#rest = rest;
4186
+ this.applicationId = applicationId;
4187
+ }
4188
+ fetchSkus() {
4189
+ return this.#rest.get(Routes.applicationSkus(this.applicationId));
4190
+ }
4191
+ async fetchEntitlements(query = {}) {
4192
+ if (query.limit !== undefined && (!Number.isInteger(query.limit) || query.limit < 1 || query.limit > 100))
4193
+ throw new RangeError("Entitlement limit must be 1-100.");
4194
+ const entitlements = await this.#rest.get(withQuery(Routes.applicationEntitlement(this.applicationId), {
4195
+ user_id: query.userId,
4196
+ sku_ids: query.skuIds?.join(","),
4197
+ guild_id: query.guildId,
4198
+ before: query.before,
4199
+ after: query.after,
4200
+ limit: query.limit,
4201
+ exclude_ended: query.excludeEnded,
4202
+ exclude_deleted: query.excludeDeleted
4203
+ }));
4204
+ for (const entitlement of entitlements)
4205
+ this.set(entitlement.id, entitlement);
4206
+ return entitlements;
4207
+ }
4208
+ async fetch(entitlementId) {
4209
+ const entitlement = await this.#rest.get(Routes.applicationEntitlement(this.applicationId, entitlementId));
4210
+ this.set(entitlement.id, entitlement);
4211
+ return entitlement;
4212
+ }
4213
+ async consume(entitlementId) {
4214
+ await this.#rest.post(Routes.consumeEntitlement(this.applicationId, entitlementId));
4215
+ const cached = this.get(entitlementId);
4216
+ if (cached)
4217
+ cached.consumed = true;
4218
+ }
4219
+ async createTestEntitlement(options) {
4220
+ const entitlement = await this.#rest.post(Routes.applicationEntitlement(this.applicationId), {
4221
+ sku_id: options.skuId,
4222
+ owner_id: options.ownerId,
4223
+ owner_type: options.ownerType
4224
+ });
4225
+ this.set(entitlement.id, entitlement);
4226
+ return entitlement;
4227
+ }
4228
+ async deleteTestEntitlement(entitlementId) {
4229
+ await this.#rest.delete(Routes.applicationEntitlement(this.applicationId, entitlementId));
4230
+ this.delete(entitlementId);
4231
+ }
4232
+ fetchSubscriptions(skuId, query = {}) {
4233
+ return this.#rest.get(withQuery(Routes.skuSubscription(skuId), {
4234
+ user_id: query.userId,
4235
+ before: query.before,
4236
+ after: query.after,
4237
+ limit: query.limit
4238
+ }));
4239
+ }
4240
+ fetchSubscription(skuId, subscriptionId) {
4241
+ return this.#rest.get(Routes.skuSubscription(skuId, subscriptionId));
4242
+ }
4243
+ }
4244
+
4245
+ // packages/managers/src/member.ts
4246
+ class GuildMemberManager extends ResourceManager {
4247
+ #rest;
4248
+ guildId;
4249
+ constructor(guildId, rest) {
4250
+ super((id) => rest.get(Routes.guildMember(guildId, id)).then((data) => new GuildMember({ ...data, guild_id: guildId })), (member) => member.user.id);
4251
+ this.guildId = guildId;
4252
+ this.#rest = rest;
4253
+ }
4254
+ async kick(userId) {
4255
+ await this.#rest.delete(Routes.guildMember(this.guildId, userId));
4256
+ this.delete(userId);
4257
+ }
4258
+ async ban(userId, options = {}) {
4259
+ await this.#rest.put(Routes.guildBan(this.guildId, userId), { delete_message_seconds: options.deleteMessageSeconds }, { reason: options.reason });
4260
+ this.delete(userId);
4261
+ }
4262
+ async unban(userId) {
4263
+ await this.#rest.delete(Routes.guildBan(this.guildId, userId));
4264
+ }
4265
+ async edit(userId, options) {
4266
+ const data = await this.#rest.patch(Routes.guildMember(this.guildId, userId), options);
4267
+ const member = new GuildMember({ ...data, guild_id: this.guildId });
4268
+ this.set(member.user.id, member);
4269
+ return member;
4270
+ }
4271
+ async addRole(userId, roleId) {
4272
+ await this.#rest.put(Routes.guildMemberRole(this.guildId, userId, roleId));
4273
+ }
4274
+ async removeRole(userId, roleId) {
4275
+ await this.#rest.delete(Routes.guildMemberRole(this.guildId, userId, roleId));
4276
+ }
4277
+ async timeout(userId, milliseconds) {
4278
+ const timeoutDate = milliseconds === null ? null : new Date(Date.now() + milliseconds).toISOString();
4279
+ return this.edit(userId, { communication_disabled_until: timeoutDate });
4280
+ }
4281
+ }
4282
+
4283
+ // packages/managers/src/role.ts
4284
+ class RoleManager extends ResourceManager {
4285
+ #rest;
4286
+ guildId;
4287
+ constructor(guildId, rest) {
4288
+ super((id) => rest.get(Routes.guildRole(guildId, id)).then((data) => new Role(data)), (role) => role.id);
4289
+ this.guildId = guildId;
4290
+ this.#rest = rest;
4291
+ }
4292
+ async fetchAll() {
4293
+ const data = await this.#rest.get(Routes.guildRoles(this.guildId));
4294
+ return data.map((item) => {
4295
+ const role = new Role(item);
4296
+ this.set(role.id, role);
4297
+ return role;
4298
+ });
4299
+ }
4300
+ async create(options) {
4301
+ const { reason, ...payload } = options;
4302
+ const data = await this.#rest.post(Routes.guildRoles(this.guildId), {
4303
+ ...payload,
4304
+ permissions: payload.permissions !== undefined ? String(payload.permissions) : undefined
4305
+ });
4306
+ const role = new Role(data);
4307
+ this.set(role.id, role);
4308
+ return role;
4309
+ }
4310
+ async edit(roleId, options) {
4311
+ const { reason, ...payload } = options;
4312
+ const data = await this.#rest.patch(Routes.guildRole(this.guildId, roleId), {
4313
+ ...payload,
4314
+ permissions: payload.permissions !== undefined ? String(payload.permissions) : undefined
4315
+ });
4316
+ const role = new Role(data);
4317
+ this.set(role.id, role);
4318
+ return role;
4319
+ }
4320
+ async deleteRole(roleId) {
4321
+ await this.#rest.delete(Routes.guildRole(this.guildId, roleId));
4322
+ this.delete(roleId);
4323
+ }
4324
+ }
4325
+
3466
4326
  // packages/managers/src/guild-resources.ts
3467
- function withQuery(path, params) {
4327
+ function withQuery2(path, params) {
3468
4328
  const query = new URLSearchParams;
3469
4329
  for (const [key, value] of Object.entries(params))
3470
4330
  if (value !== undefined)
@@ -3488,7 +4348,7 @@ class GuildBanManager extends Manager {
3488
4348
  }
3489
4349
  async fetchAll(options = {}) {
3490
4350
  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), {
4351
+ const bans = await this.#rest.get(withQuery2(Routes.guildBans(this.guildId), {
3492
4352
  limit,
3493
4353
  before: options.before,
3494
4354
  after: options.after
@@ -3521,12 +4381,12 @@ class GuildScheduledEventManager extends Manager {
3521
4381
  return event;
3522
4382
  }
3523
4383
  async fetch(eventId, options = {}) {
3524
- return this.#store(await this.#rest.get(withQuery(Routes.guildScheduledEvent(this.guildId, eventId), {
4384
+ return this.#store(await this.#rest.get(withQuery2(Routes.guildScheduledEvent(this.guildId, eventId), {
3525
4385
  with_user_count: options.withUserCount
3526
4386
  })));
3527
4387
  }
3528
4388
  async fetchAll(options = {}) {
3529
- const events = await this.#rest.get(withQuery(Routes.guildScheduledEvents(this.guildId), {
4389
+ const events = await this.#rest.get(withQuery2(Routes.guildScheduledEvents(this.guildId), {
3530
4390
  with_user_count: options.withUserCount
3531
4391
  }));
3532
4392
  return events.map((event) => this.#store(event));
@@ -3543,7 +4403,7 @@ class GuildScheduledEventManager extends Manager {
3543
4403
  }
3544
4404
  async fetchSubscribers(eventId, options = {}) {
3545
4405
  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), {
4406
+ return this.#rest.get(withQuery2(Routes.guildScheduledEventUsers(this.guildId, eventId), {
3547
4407
  limit,
3548
4408
  with_member: options.withMember,
3549
4409
  before: options.before,
@@ -3605,7 +4465,7 @@ class PermissionOverwriteManager {
3605
4465
  }
3606
4466
 
3607
4467
  // packages/managers/src/guild.ts
3608
- function withQuery2(path, params) {
4468
+ function withQuery3(path, params) {
3609
4469
  const suffix = params.toString();
3610
4470
  return suffix ? `${path}?${suffix}` : path;
3611
4471
  }
@@ -3614,22 +4474,98 @@ class GuildManager extends ResourceManager {
3614
4474
  #rest;
3615
4475
  #bans = new Map;
3616
4476
  #scheduledEvents = new Map;
4477
+ #members = new Map;
4478
+ #roles = new Map;
4479
+ #emojis = new Map;
4480
+ #stickers = new Map;
4481
+ #soundboard = new Map;
4482
+ #voiceStates = new Map;
4483
+ #autoModerationRules = new Map;
4484
+ #invites = new Map;
4485
+ #perGuild(map, guildId, create) {
4486
+ let manager = map.get(guildId);
4487
+ if (!manager)
4488
+ map.set(guildId, manager = create());
4489
+ return manager;
4490
+ }
3617
4491
  constructor(rest) {
3618
4492
  super(async (id) => new Guild(await rest.get(Routes.guild(id))), (guild) => guild.id);
3619
4493
  this.#rest = rest;
3620
4494
  }
3621
- bans(guildId) {
3622
- let manager = this.#bans.get(guildId);
4495
+ bans(guildId) {
4496
+ let manager = this.#bans.get(guildId);
4497
+ if (!manager)
4498
+ this.#bans.set(guildId, manager = new GuildBanManager(this.#rest, guildId));
4499
+ return manager;
4500
+ }
4501
+ scheduledEvents(guildId) {
4502
+ let manager = this.#scheduledEvents.get(guildId);
4503
+ if (!manager)
4504
+ this.#scheduledEvents.set(guildId, manager = new GuildScheduledEventManager(this.#rest, guildId));
4505
+ return manager;
4506
+ }
4507
+ members(guildId) {
4508
+ let manager = this.#members.get(guildId);
4509
+ if (!manager)
4510
+ this.#members.set(guildId, manager = new GuildMemberManager(guildId, this.#rest));
4511
+ return manager;
4512
+ }
4513
+ roles(guildId) {
4514
+ let manager = this.#roles.get(guildId);
3623
4515
  if (!manager)
3624
- this.#bans.set(guildId, manager = new GuildBanManager(this.#rest, guildId));
4516
+ this.#roles.set(guildId, manager = new RoleManager(guildId, this.#rest));
3625
4517
  return manager;
3626
4518
  }
3627
- scheduledEvents(guildId) {
3628
- let manager = this.#scheduledEvents.get(guildId);
4519
+ emojis(guildId) {
4520
+ let manager = this.#emojis.get(guildId);
3629
4521
  if (!manager)
3630
- this.#scheduledEvents.set(guildId, manager = new GuildScheduledEventManager(this.#rest, guildId));
4522
+ this.#emojis.set(guildId, manager = new EmojiManager(this.#rest, guildId));
3631
4523
  return manager;
3632
4524
  }
4525
+ stickers(guildId) {
4526
+ let manager = this.#stickers.get(guildId);
4527
+ if (!manager)
4528
+ this.#stickers.set(guildId, manager = new GuildStickerManager(this.#rest, guildId));
4529
+ return manager;
4530
+ }
4531
+ soundboard(guildId) {
4532
+ let manager = this.#soundboard.get(guildId);
4533
+ if (!manager)
4534
+ this.#soundboard.set(guildId, manager = new GuildSoundboardManager(this.#rest, guildId));
4535
+ return manager;
4536
+ }
4537
+ voiceStates(guildId) {
4538
+ return this.#perGuild(this.#voiceStates, guildId, () => new Manager);
4539
+ }
4540
+ autoModerationRules(guildId) {
4541
+ return this.#perGuild(this.#autoModerationRules, guildId, () => new Manager);
4542
+ }
4543
+ invites(guildId) {
4544
+ return this.#perGuild(this.#invites, guildId, () => new Manager);
4545
+ }
4546
+ patch(data) {
4547
+ const guild = new Guild(data);
4548
+ const existing = this.get(guild.id);
4549
+ if (!existing)
4550
+ return this.upsert(guild);
4551
+ for (const [key, value] of Object.entries(guild))
4552
+ if (value !== undefined)
4553
+ existing[key] = value;
4554
+ return existing;
4555
+ }
4556
+ delete(id) {
4557
+ this.#bans.delete(id);
4558
+ this.#scheduledEvents.delete(id);
4559
+ this.#members.delete(id);
4560
+ this.#roles.delete(id);
4561
+ this.#emojis.delete(id);
4562
+ this.#stickers.delete(id);
4563
+ this.#soundboard.delete(id);
4564
+ this.#voiceStates.delete(id);
4565
+ this.#autoModerationRules.delete(id);
4566
+ this.#invites.delete(id);
4567
+ return super.delete(id);
4568
+ }
3633
4569
  async create(options) {
3634
4570
  const data = await this.#rest.post("/guilds", options);
3635
4571
  return this.upsert(new Guild(data));
@@ -3665,7 +4601,7 @@ class GuildManager extends ResourceManager {
3665
4601
  params.set("after", options.after);
3666
4602
  if (options.limit !== undefined)
3667
4603
  params.set("limit", String(Math.min(100, Math.max(1, options.limit))));
3668
- return this.#rest.get(withQuery2(Routes.guildAuditLog(guildId), params));
4604
+ return this.#rest.get(withQuery3(Routes.guildAuditLog(guildId), params));
3669
4605
  }
3670
4606
  async fetchMembers(guildId, options = {}) {
3671
4607
  const params = new URLSearchParams;
@@ -3673,7 +4609,7 @@ class GuildManager extends ResourceManager {
3673
4609
  params.set("limit", String(Math.min(1000, Math.max(1, options.limit))));
3674
4610
  if (options.after)
3675
4611
  params.set("after", options.after);
3676
- return this.#rest.get(withQuery2(Routes.guildMembers(guildId), params));
4612
+ return this.#rest.get(withQuery3(Routes.guildMembers(guildId), params));
3677
4613
  }
3678
4614
  async fetchAutoModerationRules(guildId) {
3679
4615
  const rules = await this.#rest.get(Routes.guildAutoModerationRules(guildId));
@@ -3748,85 +4684,6 @@ var AuditLogEvent = {
3748
4684
  AutoModerationRuleDelete: 142,
3749
4685
  AutoModerationBlockMessage: 143
3750
4686
  };
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;
3818
- }
3819
- async addRole(userId, roleId) {
3820
- await this.#rest.put(Routes.guildMemberRole(this.guildId, userId, roleId));
3821
- }
3822
- async removeRole(userId, roleId) {
3823
- await this.#rest.delete(Routes.guildMemberRole(this.guildId, userId, roleId));
3824
- }
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 });
3828
- }
3829
- }
3830
4687
  // packages/managers/src/application.ts
3831
4688
  class ApplicationCommandManager {
3832
4689
  #rest;
@@ -3866,53 +4723,22 @@ class ApplicationCommandManager {
3866
4723
  await this.#rest.delete(Routes.guildApplicationCommand(this.#applicationId, guildId, commandId));
3867
4724
  }
3868
4725
  }
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
4726
 
3908
4727
  // packages/managers/src/index.ts
4728
+ var BULK_DELETE_MAX_AGE_MS = 14 * 24 * 60 * 60000;
4729
+ function snowflakeTime(id) {
4730
+ return Number((BigInt(id) >> 22n) + 1420070400000n);
4731
+ }
4732
+
3909
4733
  class ChannelManager extends Manager {
3910
4734
  #rest;
3911
4735
  #context;
3912
4736
  #messageManagers = new Map;
3913
- constructor(rest) {
4737
+ #messageCache;
4738
+ constructor(rest, options = {}) {
3914
4739
  super();
3915
4740
  this.#rest = rest;
4741
+ this.#messageCache = options.messageCache;
3916
4742
  this.#context = {
3917
4743
  sendMessage: (channelId, options) => this.send(channelId, options),
3918
4744
  editMessage: (channelId, messageId, options) => this.editMessage(channelId, messageId, options),
@@ -3931,7 +4757,7 @@ class ChannelManager extends Manager {
3931
4757
  messages(channelId) {
3932
4758
  let manager = this.#messageManagers.get(channelId);
3933
4759
  if (!manager) {
3934
- manager = new MessageManager(this.#rest, this.#context, channelId);
4760
+ manager = new MessageManager(this.#rest, this.#context, channelId, this.#messageCache);
3935
4761
  this.#messageManagers.set(channelId, manager);
3936
4762
  }
3937
4763
  return manager;
@@ -3942,16 +4768,18 @@ class ChannelManager extends Manager {
3942
4768
  threads(channelId) {
3943
4769
  return new ThreadManager(this.#rest, this.#context, channelId);
3944
4770
  }
3945
- async fetch(channelId) {
3946
- return this.upsert(await this.#rest.get(Routes.channel(channelId)));
4771
+ fetch(channelId) {
4772
+ return this.fetchOnce(channelId, async () => createChannel(await this.#rest.get(Routes.channel(channelId)), this.#context), (channel) => this.#merge(channel));
3947
4773
  }
3948
4774
  async resolve(channelId) {
3949
4775
  return this.get(channelId) ?? this.fetch(channelId);
3950
4776
  }
3951
4777
  upsert(data) {
3952
- const existing = this.get(data.id);
3953
- const channel = createChannel(data, this.#context);
3954
- if (existing) {
4778
+ return this.#merge(createChannel(data, this.#context));
4779
+ }
4780
+ #merge(channel) {
4781
+ const existing = this.get(channel.id);
4782
+ if (existing && existing.type === channel.type) {
3955
4783
  Object.assign(existing, channel);
3956
4784
  return existing;
3957
4785
  }
@@ -3961,6 +4789,37 @@ class ChannelManager extends Manager {
3961
4789
  update(channel) {
3962
4790
  return this.set(channel.id, channel);
3963
4791
  }
4792
+ deleteGuildChannels(guildId) {
4793
+ let removed = 0;
4794
+ for (const channel of this.values())
4795
+ if (channel.guildId === guildId && this.delete(channel.id))
4796
+ removed++;
4797
+ return removed;
4798
+ }
4799
+ async endPoll(channelId, messageId) {
4800
+ return this.messages(channelId).upsert(await this.#rest.post(Routes.pollExpire(channelId, messageId)));
4801
+ }
4802
+ async fetchPollVoters(channelId, messageId, answerId, options = {}) {
4803
+ if (options.limit !== undefined && (!Number.isInteger(options.limit) || options.limit < 1 || options.limit > 100))
4804
+ throw new RangeError("Poll voter limit must be 1-100.");
4805
+ const params = new URLSearchParams;
4806
+ if (options.after)
4807
+ params.set("after", options.after);
4808
+ if (options.limit !== undefined)
4809
+ params.set("limit", String(options.limit));
4810
+ const suffix = params.toString();
4811
+ const { users } = await this.#rest.get(`${Routes.pollAnswerVoters(channelId, messageId, answerId)}${suffix ? `?${suffix}` : ""}`);
4812
+ return users.map((user) => new User(user));
4813
+ }
4814
+ async sendSoundboardSound(channelId, options) {
4815
+ await this.#rest.post(Routes.sendSoundboardSound(channelId), {
4816
+ sound_id: options.soundId,
4817
+ source_guild_id: options.sourceGuildId
4818
+ });
4819
+ }
4820
+ cachedMessages(channelId) {
4821
+ return this.#messageManagers.get(channelId);
4822
+ }
3964
4823
  async create(guildId, options) {
3965
4824
  return this.upsert(await this.#rest.post(Routes.guildChannels(guildId), options));
3966
4825
  }
@@ -4017,15 +4876,37 @@ class ChannelManager extends Manager {
4017
4876
  return this.messages(channelId).upsert(await this.#rest.post(Routes.crosspostMessage(channelId, messageId)));
4018
4877
  }
4019
4878
  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.");
4879
+ const ids = [...new Set(messageIds)];
4880
+ if (ids.length < 1 || ids.length > 100)
4881
+ throw new RangeError("bulkDelete requires between 1 and 100 message IDs.");
4882
+ if (ids.length === 1)
4883
+ return this.deleteMessage(channelId, ids[0]);
4884
+ const cutoff = Date.now() - BULK_DELETE_MAX_AGE_MS;
4885
+ const tooOld = ids.filter((id) => snowflakeTime(id) < cutoff);
4886
+ if (tooOld.length)
4887
+ throw new RangeError(`bulkDelete cannot delete messages older than 14 days: ${tooOld.join(", ")}`);
4023
4888
  await this.#rest.post(Routes.channelBulkDelete(channelId), {
4024
4889
  messages: ids
4025
4890
  });
4026
4891
  for (const id of ids)
4027
4892
  this.messages(channelId).delete(id);
4028
4893
  }
4894
+ async* iterateMessages(channelId, options = {}) {
4895
+ let before = options.before;
4896
+ let remaining = options.limit ?? Infinity;
4897
+ while (remaining > 0) {
4898
+ const page = await this.fetchMessages(channelId, {
4899
+ before,
4900
+ limit: Math.min(100, remaining)
4901
+ });
4902
+ for (const message of page)
4903
+ yield message;
4904
+ remaining -= page.length;
4905
+ if (page.length < 100)
4906
+ return;
4907
+ before = page.at(-1).id;
4908
+ }
4909
+ }
4029
4910
  async addReaction(channelId, messageId, emoji) {
4030
4911
  await this.#rest.put(`${Routes.messageReactions(channelId, messageId, emoji)}/@me`);
4031
4912
  }
@@ -4121,6 +5002,8 @@ class GatewaySession {
4121
5002
  return false;
4122
5003
  if (!Number.isInteger(sequence))
4123
5004
  return false;
5005
+ if (this.#sequence !== null && sequence < this.#sequence)
5006
+ return false;
4124
5007
  this.#sequence = sequence;
4125
5008
  return true;
4126
5009
  }
@@ -4219,8 +5102,11 @@ class GatewayHeartbeat {
4219
5102
  this.#clearBeatTimers();
4220
5103
  this.#interval = interval;
4221
5104
  this.#acknowledged = true;
4222
- this.#initialTimer = setTimeout(() => this.sendHeartbeat(), Math.random() * interval);
4223
- this.#timer = setInterval(() => this.sendHeartbeat(), interval);
5105
+ this.#initialTimer = setTimeout(() => {
5106
+ this.#initialTimer = undefined;
5107
+ this.sendHeartbeat();
5108
+ this.#timer = setInterval(() => this.sendHeartbeat(), interval);
5109
+ }, Math.random() * interval);
4224
5110
  }
4225
5111
  stop() {
4226
5112
  this.#clearBeatTimers();
@@ -4246,6 +5132,8 @@ class GatewayHeartbeat {
4246
5132
  }, this.#options.ackTimeout);
4247
5133
  }
4248
5134
  acknowledge() {
5135
+ if (this.#acknowledged)
5136
+ return;
4249
5137
  this.#acknowledged = true;
4250
5138
  this.#latency = this.#now() - this.#sentAt;
4251
5139
  this.#clearAckTimer();
@@ -4826,6 +5714,7 @@ class SendBudget {
4826
5714
  }
4827
5715
 
4828
5716
  // packages/ws/src/index.ts
5717
+ var RESUMABLE_CLOSE_CODE = 4900;
4829
5718
  var DEFAULT_GATEWAY_URL = "wss://gateway.discord.gg/?v=10&encoding=json";
4830
5719
 
4831
5720
  class Gateway {
@@ -4911,7 +5800,7 @@ class Gateway {
4911
5800
  } else {
4912
5801
  this.#emitError(new GatewayError(`Gateway heartbeat acknowledgement timed out after ${timeout.elapsedMs}ms.`));
4913
5802
  }
4914
- this.#transport.close(1001, timeout.type === "zombie" ? "Zombie Gateway connection" : "Heartbeat timeout");
5803
+ this.#transport.close(RESUMABLE_CLOSE_CODE, timeout.type === "zombie" ? "Zombie Gateway connection" : "Heartbeat timeout");
4915
5804
  }
4916
5805
  connect(url = DEFAULT_GATEWAY_URL) {
4917
5806
  if (this.state === "CLOSED" /* Closed */)
@@ -5047,7 +5936,7 @@ class Gateway {
5047
5936
  this.#emit("heartbeatAck", action.data);
5048
5937
  return;
5049
5938
  case "reconnect":
5050
- this.#transport.close(1001, "Server requested reconnect");
5939
+ this.#transport.close(RESUMABLE_CLOSE_CODE, "Server requested reconnect");
5051
5940
  return;
5052
5941
  case "invalid-session": {
5053
5942
  if (!action.resumable)
@@ -5241,6 +6130,7 @@ class Client extends EventEmitter2 {
5241
6130
  channels;
5242
6131
  stageInstances;
5243
6132
  application;
6133
+ monetization;
5244
6134
  get ws() {
5245
6135
  return this.#gateway;
5246
6136
  }
@@ -5272,6 +6162,7 @@ class Client extends EventEmitter2 {
5272
6162
  return this.#gateway.requestGuildMembers(data);
5273
6163
  }
5274
6164
  #gateway;
6165
+ #cache;
5275
6166
  #resourceContext;
5276
6167
  constructor(options) {
5277
6168
  super();
@@ -5279,9 +6170,18 @@ class Client extends EventEmitter2 {
5279
6170
  if (!options.token?.trim())
5280
6171
  throw new TypeError("Client token is required.");
5281
6172
  this.rest = new REST({ token: options.token, ...options.rest });
6173
+ this.#cache = {
6174
+ users: true,
6175
+ members: true,
6176
+ roles: true,
6177
+ emojis: true,
6178
+ ...options.cache
6179
+ };
5282
6180
  this.users = new UserManager(this.rest);
5283
6181
  this.guilds = new GuildManager(this.rest);
5284
- this.channels = new ChannelManager(this.rest);
6182
+ this.channels = new ChannelManager(this.rest, {
6183
+ messageCache: options.messageCache
6184
+ });
5285
6185
  this.stageInstances = new StageInstanceManager(this.rest);
5286
6186
  const placeholderAppCommands = new ApplicationCommandManager(this.rest, "0");
5287
6187
  this.application = { commands: placeholderAppCommands };
@@ -5312,6 +6212,8 @@ class Client extends EventEmitter2 {
5312
6212
  this.state = "ready";
5313
6213
  const appId = ready.application?.id ?? this.user.id;
5314
6214
  this.application.commands = new ApplicationCommandManager(this.rest, appId);
6215
+ if (this.monetization?.applicationId !== appId)
6216
+ this.monetization = new MonetizationManager(this.rest, appId);
5315
6217
  this.emit("ready" /* Ready */, this.user);
5316
6218
  });
5317
6219
  this.#gateway.on("RESUMED", () => {
@@ -5329,18 +6231,39 @@ class Client extends EventEmitter2 {
5329
6231
  });
5330
6232
  this.#gateway.on("MESSAGE_CREATE", (data) => {
5331
6233
  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);
6234
+ this.#observeMessage(message);
6235
+ const cached = this.options.messageCache ? this.channels.messages(message.channelId).upsert(data) : message;
6236
+ this.emit("messageCreate" /* MessageCreate */, cached);
5335
6237
  });
5336
6238
  this.#gateway.on("MESSAGE_UPDATE", (data) => {
5337
6239
  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);
6240
+ this.#observeMessage(message);
6241
+ const messages = this.channels.cachedMessages(message.channelId);
6242
+ const previous = messages?.cache.peek(message.id);
6243
+ if (previous)
6244
+ messages.cache.set(message.id, message);
6245
+ this.emit("messageUpdate" /* MessageUpdate */, message, previous);
6246
+ });
6247
+ this.#gateway.on("MESSAGE_DELETE", (data) => {
6248
+ const payload = data;
6249
+ const messages = this.channels.cachedMessages(payload.channel_id);
6250
+ const removed = messages?.cache.peek(payload.id);
6251
+ messages?.delete(payload.id);
6252
+ this.emit("messageDelete" /* MessageDelete */, payload, removed);
6253
+ });
6254
+ this.#gateway.on("MESSAGE_DELETE_BULK", (data) => {
6255
+ const payload = data;
6256
+ const messages = this.channels.cachedMessages(payload.channel_id);
6257
+ const removed = [];
6258
+ if (messages)
6259
+ for (const id of payload.ids) {
6260
+ const message = messages.cache.peek(id);
6261
+ if (message)
6262
+ removed.push(message);
6263
+ messages.delete(id);
6264
+ }
6265
+ this.emit("messageDeleteBulk" /* MessageDeleteBulk */, payload, removed);
5341
6266
  });
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
6267
  this.#gateway.on("MESSAGE_REACTION_ADD", (data) => this.emit("messageReactionAdd" /* MessageReactionAdd */, data));
5345
6268
  this.#gateway.on("MESSAGE_REACTION_REMOVE", (data) => this.emit("messageReactionRemove" /* MessageReactionRemove */, data));
5346
6269
  this.#gateway.on("MESSAGE_REACTION_REMOVE_ALL", (data) => this.emit("messageReactionRemoveAll" /* MessageReactionRemoveAll */, data));
@@ -5354,20 +6277,27 @@ class Client extends EventEmitter2 {
5354
6277
  return;
5355
6278
  }
5356
6279
  const wasCached = this.guilds.has(payload.id);
5357
- const guild = new Guild(payload);
5358
- this.guilds.set(guild.id, guild);
6280
+ this.guilds.patch(payload);
6281
+ for (const role of payload.roles ?? [])
6282
+ this.#upsertRole(payload.id, role);
6283
+ if (this.#cache.emojis) {
6284
+ const emojis = this.guilds.emojis(payload.id);
6285
+ for (const emoji of payload.emojis ?? [])
6286
+ emojis.upsert(emoji);
6287
+ }
5359
6288
  for (const member of payload.members ?? [])
5360
- this.users.set(member.user.id, new User(member.user));
6289
+ this.#upsertMember(payload.id, member);
6290
+ for (const state of payload.voice_states ?? [])
6291
+ this.#storeVoiceState(payload.id, state);
5361
6292
  for (const channelData of [
5362
6293
  ...payload.channels ?? [],
5363
6294
  ...payload.threads ?? []
5364
6295
  ])
5365
- this.channels.set(channelData.id, createChannel(channelData, this.#resourceContext));
6296
+ this.channels.upsert({ ...channelData, guild_id: payload.id });
5366
6297
  this.emit(wasCached ? "guildAvailable" /* GuildAvailable */ : "guildCreate" /* GuildCreate */, payload);
5367
6298
  });
5368
6299
  this.#gateway.on("GUILD_UPDATE", (data) => {
5369
- const guild = new Guild(data);
5370
- this.guilds.update(guild);
6300
+ this.guilds.patch(data);
5371
6301
  this.emit("guildUpdate" /* GuildUpdate */, data);
5372
6302
  });
5373
6303
  this.#gateway.on("GUILD_DELETE", (data) => {
@@ -5377,45 +6307,158 @@ class Client extends EventEmitter2 {
5377
6307
  return;
5378
6308
  }
5379
6309
  this.guilds.delete(payload.id);
6310
+ this.channels.deleteGuildChannels(payload.id);
5380
6311
  this.emit("guildDelete" /* GuildDelete */, payload);
5381
6312
  });
5382
6313
  this.#gateway.on("GUILD_MEMBER_ADD", (data) => {
5383
6314
  const member = data;
5384
- this.users.set(member.user.id, new User(member.user));
6315
+ this.#upsertMember(member.guild_id, member);
5385
6316
  this.emit("guildMemberAdd" /* GuildMemberAdd */, member);
5386
6317
  });
5387
6318
  this.#gateway.on("GUILD_MEMBER_UPDATE", (data) => {
5388
6319
  const member = data;
5389
- this.users.set(member.user.id, new User(member.user));
6320
+ this.#upsertMember(member.guild_id, member);
5390
6321
  this.emit("guildMemberUpdate" /* GuildMemberUpdate */, member);
5391
6322
  });
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));
6323
+ this.#gateway.on("GUILD_MEMBER_REMOVE", (data) => {
6324
+ const member = data;
6325
+ this.guilds.members(member.guild_id).delete(member.user.id);
6326
+ this.emit("guildMemberRemove" /* GuildMemberRemove */, member);
6327
+ });
6328
+ this.#gateway.on("GUILD_MEMBERS_CHUNK", (data) => {
6329
+ const chunk = data;
6330
+ for (const member of chunk.members)
6331
+ this.#upsertMember(chunk.guild_id, member);
6332
+ this.emit("guildMembersChunk" /* GuildMembersChunk */, chunk);
6333
+ });
6334
+ this.#gateway.on("GUILD_BAN_ADD", (data) => {
6335
+ const ban = data;
6336
+ const bans = this.guilds.bans(ban.guild_id);
6337
+ bans.set(ban.user.id, {
6338
+ reason: bans.get(ban.user.id)?.reason ?? null,
6339
+ user: ban.user
6340
+ });
6341
+ this.guilds.members(ban.guild_id).delete(ban.user.id);
6342
+ this.emit("guildBanAdd" /* GuildBanAdd */, ban);
6343
+ });
6344
+ this.#gateway.on("GUILD_BAN_REMOVE", (data) => {
6345
+ const ban = data;
6346
+ this.guilds.bans(ban.guild_id).delete(ban.user.id);
6347
+ this.emit("guildBanRemove" /* GuildBanRemove */, ban);
6348
+ });
6349
+ this.#gateway.on("GUILD_ROLE_CREATE", (data) => {
6350
+ const event = data;
6351
+ this.#upsertRole(event.guild_id, event.role);
6352
+ this.emit("guildRoleCreate" /* GuildRoleCreate */, event);
6353
+ });
6354
+ this.#gateway.on("GUILD_ROLE_UPDATE", (data) => {
6355
+ const event = data;
6356
+ this.#upsertRole(event.guild_id, event.role);
6357
+ this.emit("guildRoleUpdate" /* GuildRoleUpdate */, event);
6358
+ });
6359
+ this.#gateway.on("GUILD_ROLE_DELETE", (data) => {
6360
+ const event = data;
6361
+ this.guilds.roles(event.guild_id).delete(event.role_id);
6362
+ this.emit("guildRoleDelete" /* GuildRoleDelete */, event);
6363
+ });
6364
+ this.#gateway.on("GUILD_EMOJIS_UPDATE", (data) => {
6365
+ const event = data;
6366
+ if (this.#cache.emojis) {
6367
+ const emojis = this.guilds.emojis(event.guild_id);
6368
+ const current = new Set(event.emojis.map((emoji) => emoji.id));
6369
+ for (const id of [...emojis.cache.keys()])
6370
+ if (!current.has(id))
6371
+ emojis.delete(id);
6372
+ for (const emoji of event.emojis)
6373
+ emojis.upsert(emoji);
6374
+ }
6375
+ this.emit("guildEmojisUpdate" /* GuildEmojisUpdate */, event);
6376
+ });
6377
+ this.#gateway.on("GUILD_STICKERS_UPDATE", (data) => {
6378
+ const event = data;
6379
+ this.guilds.stickers(event.guild_id).sync(event.stickers);
6380
+ this.emit("guildStickersUpdate" /* GuildStickersUpdate */, event);
6381
+ });
6382
+ this.#gateway.on("GUILD_SOUNDBOARD_SOUND_CREATE", (data) => {
6383
+ const sound = data;
6384
+ if (sound.guild_id)
6385
+ this.guilds.soundboard(sound.guild_id).set(sound.sound_id, sound);
6386
+ this.emit("soundboardSoundCreate" /* SoundboardSoundCreate */, sound);
6387
+ });
6388
+ this.#gateway.on("GUILD_SOUNDBOARD_SOUND_UPDATE", (data) => {
6389
+ const sound = data;
6390
+ if (sound.guild_id)
6391
+ this.guilds.soundboard(sound.guild_id).set(sound.sound_id, sound);
6392
+ this.emit("soundboardSoundUpdate" /* SoundboardSoundUpdate */, sound);
6393
+ });
6394
+ this.#gateway.on("GUILD_SOUNDBOARD_SOUND_DELETE", (data) => {
6395
+ const event = data;
6396
+ this.guilds.soundboard(event.guild_id).delete(event.sound_id);
6397
+ this.emit("soundboardSoundDelete" /* SoundboardSoundDelete */, event);
6398
+ });
6399
+ this.#gateway.on("GUILD_SOUNDBOARD_SOUNDS_UPDATE", (data) => {
6400
+ const event = data;
6401
+ const sounds = this.guilds.soundboard(event.guild_id);
6402
+ sounds.clear();
6403
+ for (const sound of event.soundboard_sounds)
6404
+ sounds.set(sound.sound_id, sound);
6405
+ this.emit("soundboardSoundsUpdate" /* SoundboardSoundsUpdate */, event);
6406
+ });
6407
+ this.#gateway.on("ENTITLEMENT_CREATE", (data) => {
6408
+ const entitlement = data;
6409
+ this.monetization?.set(entitlement.id, entitlement);
6410
+ this.emit("entitlementCreate" /* EntitlementCreate */, entitlement);
6411
+ });
6412
+ this.#gateway.on("ENTITLEMENT_UPDATE", (data) => {
6413
+ const entitlement = data;
6414
+ this.monetization?.set(entitlement.id, entitlement);
6415
+ this.emit("entitlementUpdate" /* EntitlementUpdate */, entitlement);
6416
+ });
6417
+ this.#gateway.on("ENTITLEMENT_DELETE", (data) => {
6418
+ const entitlement = data;
6419
+ this.monetization?.delete(entitlement.id);
6420
+ this.emit("entitlementDelete" /* EntitlementDelete */, entitlement);
6421
+ });
5401
6422
  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));
6423
+ this.#gateway.on("GUILD_SCHEDULED_EVENT_CREATE", (data) => {
6424
+ const event = data;
6425
+ this.guilds.scheduledEvents(event.guild_id).set(event.id, event);
6426
+ this.emit("guildScheduledEventCreate" /* GuildScheduledEventCreate */, event);
6427
+ });
6428
+ this.#gateway.on("GUILD_SCHEDULED_EVENT_UPDATE", (data) => {
6429
+ const event = data;
6430
+ this.guilds.scheduledEvents(event.guild_id).set(event.id, event);
6431
+ this.emit("guildScheduledEventUpdate" /* GuildScheduledEventUpdate */, event);
6432
+ });
6433
+ this.#gateway.on("GUILD_SCHEDULED_EVENT_DELETE", (data) => {
6434
+ const event = data;
6435
+ this.guilds.scheduledEvents(event.guild_id).delete(event.id);
6436
+ this.emit("guildScheduledEventDelete" /* GuildScheduledEventDelete */, event);
6437
+ });
5405
6438
  this.#gateway.on("GUILD_SCHEDULED_EVENT_USER_ADD", (data) => this.emit("guildScheduledEventUserAdd" /* GuildScheduledEventUserAdd */, data));
5406
6439
  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));
6440
+ this.#gateway.on("AUTO_MODERATION_RULE_CREATE", (data) => {
6441
+ const rule = data;
6442
+ this.guilds.autoModerationRules(rule.guild_id).set(rule.id, rule);
6443
+ this.emit("autoModerationRuleCreate" /* AutoModerationRuleCreate */, rule);
6444
+ });
6445
+ this.#gateway.on("AUTO_MODERATION_RULE_UPDATE", (data) => {
6446
+ const rule = data;
6447
+ this.guilds.autoModerationRules(rule.guild_id).set(rule.id, rule);
6448
+ this.emit("autoModerationRuleUpdate" /* AutoModerationRuleUpdate */, rule);
6449
+ });
6450
+ this.#gateway.on("AUTO_MODERATION_RULE_DELETE", (data) => {
6451
+ const rule = data;
6452
+ this.guilds.autoModerationRules(rule.guild_id).delete(rule.id);
6453
+ this.emit("autoModerationRuleDelete" /* AutoModerationRuleDelete */, rule);
6454
+ });
5410
6455
  this.#gateway.on("AUTO_MODERATION_ACTION_EXECUTION", (data) => this.emit("autoModerationActionExecution" /* AutoModerationActionExecution */, data));
5411
6456
  this.#gateway.on("CHANNEL_CREATE", (data) => {
5412
- const channel = createChannel(data, this.#resourceContext);
5413
- this.channels.update(channel);
6457
+ const channel = this.channels.upsert(data);
5414
6458
  this.emit("channelCreate" /* ChannelCreate */, channel);
5415
6459
  });
5416
6460
  this.#gateway.on("CHANNEL_UPDATE", (data) => {
5417
- const channel = createChannel(data, this.#resourceContext);
5418
- this.channels.update(channel);
6461
+ const channel = this.channels.upsert(data);
5419
6462
  this.emit("channelUpdate" /* ChannelUpdate */, channel);
5420
6463
  });
5421
6464
  this.#gateway.on("CHANNEL_DELETE", (data) => {
@@ -5425,13 +6468,11 @@ class Client extends EventEmitter2 {
5425
6468
  });
5426
6469
  this.#gateway.on("CHANNEL_PINS_UPDATE", (data) => this.emit("channelPinsUpdate" /* ChannelPinsUpdate */, data));
5427
6470
  this.#gateway.on("THREAD_CREATE", (data) => {
5428
- const channel = createChannel(data, this.#resourceContext);
5429
- this.channels.update(channel);
6471
+ const channel = this.channels.upsert(data);
5430
6472
  this.emit("threadCreate" /* ThreadCreate */, channel);
5431
6473
  });
5432
6474
  this.#gateway.on("THREAD_UPDATE", (data) => {
5433
- const channel = createChannel(data, this.#resourceContext);
5434
- this.channels.update(channel);
6475
+ const channel = this.channels.upsert(data);
5435
6476
  this.emit("threadUpdate" /* ThreadUpdate */, channel);
5436
6477
  });
5437
6478
  this.#gateway.on("THREAD_DELETE", (data) => {
@@ -5439,16 +6480,48 @@ class Client extends EventEmitter2 {
5439
6480
  this.channels.delete(payload.id);
5440
6481
  this.emit("threadDelete" /* ThreadDelete */, payload);
5441
6482
  });
5442
- this.#gateway.on("THREAD_LIST_SYNC", (data) => this.emit("threadListSync" /* ThreadListSync */, data));
6483
+ this.#gateway.on("THREAD_LIST_SYNC", (data) => {
6484
+ const sync = data;
6485
+ for (const thread of sync.threads)
6486
+ this.channels.upsert({ ...thread, guild_id: sync.guild_id });
6487
+ this.emit("threadListSync" /* ThreadListSync */, sync);
6488
+ });
5443
6489
  this.#gateway.on("THREAD_MEMBERS_UPDATE", (data) => this.emit("threadMembersUpdate" /* ThreadMembersUpdate */, data));
5444
6490
  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));
6491
+ this.#gateway.on("STAGE_INSTANCE_CREATE", (data) => {
6492
+ const stage = data;
6493
+ this.stageInstances.set(stage.channel_id, stage);
6494
+ this.emit("stageInstanceCreate" /* StageInstanceCreate */, stage);
6495
+ });
6496
+ this.#gateway.on("STAGE_INSTANCE_UPDATE", (data) => {
6497
+ const stage = data;
6498
+ this.stageInstances.set(stage.channel_id, stage);
6499
+ this.emit("stageInstanceUpdate" /* StageInstanceUpdate */, stage);
6500
+ });
6501
+ this.#gateway.on("STAGE_INSTANCE_DELETE", (data) => {
6502
+ const stage = data;
6503
+ this.stageInstances.delete(stage.channel_id);
6504
+ this.emit("stageInstanceDelete" /* StageInstanceDelete */, stage);
6505
+ });
6506
+ this.#gateway.on("INVITE_CREATE", (data) => {
6507
+ const invite = data;
6508
+ if (invite.guild_id)
6509
+ this.guilds.invites(invite.guild_id).set(invite.code, invite);
6510
+ this.emit("inviteCreate" /* InviteCreate */, invite);
6511
+ });
6512
+ this.#gateway.on("INVITE_DELETE", (data) => {
6513
+ const invite = data;
6514
+ if (invite.guild_id)
6515
+ this.guilds.invites(invite.guild_id).delete(invite.code);
6516
+ this.emit("inviteDelete" /* InviteDelete */, invite);
6517
+ });
5450
6518
  this.#gateway.on("WEBHOOKS_UPDATE", (data) => this.emit("webhooksUpdate" /* WebhooksUpdate */, data));
5451
- this.#gateway.on("VOICE_STATE_UPDATE", (data) => this.emit("voiceStateUpdate" /* VoiceStateUpdate */, data));
6519
+ this.#gateway.on("VOICE_STATE_UPDATE", (data) => {
6520
+ const state = data;
6521
+ if (state.guild_id)
6522
+ this.#storeVoiceState(state.guild_id, state);
6523
+ this.emit("voiceStateUpdate" /* VoiceStateUpdate */, state);
6524
+ });
5452
6525
  this.#gateway.on("VOICE_SERVER_UPDATE", (data) => this.emit("voiceServerUpdate" /* VoiceServerUpdate */, data));
5453
6526
  this.#gateway.on("PRESENCE_UPDATE", (data) => this.emit("presenceUpdate" /* PresenceUpdate */, data));
5454
6527
  this.#gateway.on("TYPING_START", (data) => this.emit("typingStart" /* TypingStart */, data));
@@ -5456,6 +6529,80 @@ class Client extends EventEmitter2 {
5456
6529
  this.#gateway.on("RAW", (data) => this.emit("raw" /* Raw */, data));
5457
6530
  this.#gateway.on("error", (error) => this.emit("error" /* Error */, error));
5458
6531
  }
6532
+ #observeMessage(message) {
6533
+ if (!this.channels.has(message.channelId))
6534
+ this.channels.set(message.channelId, message.channel);
6535
+ if (this.#cache.users)
6536
+ this.#merge(this.users, message.author.id, message.author);
6537
+ }
6538
+ #upsertMember(guildId, data) {
6539
+ const member = new GuildMember({ ...data, guild_id: guildId });
6540
+ if (this.#cache.users)
6541
+ this.#merge(this.users, member.user.id, member.user);
6542
+ if (!this.#cache.members)
6543
+ return member;
6544
+ return this.#merge(this.guilds.members(guildId), member.user.id, member);
6545
+ }
6546
+ #storeVoiceState(guildId, state) {
6547
+ const states = this.guilds.voiceStates(guildId);
6548
+ if (state.channel_id)
6549
+ states.set(state.user_id, state);
6550
+ else
6551
+ states.delete(state.user_id);
6552
+ }
6553
+ #upsertRole(guildId, data) {
6554
+ if (!this.#cache.roles)
6555
+ return new Role(data);
6556
+ return this.#merge(this.guilds.roles(guildId), data.id, new Role(data));
6557
+ }
6558
+ #merge(manager, id, next) {
6559
+ const existing = manager.get(id);
6560
+ if (!existing) {
6561
+ manager.set(id, next);
6562
+ return next;
6563
+ }
6564
+ for (const [key, value] of Object.entries(next))
6565
+ if (value !== undefined)
6566
+ existing[key] = value;
6567
+ return existing;
6568
+ }
6569
+ createCollector(event, options = {}) {
6570
+ const collector = new Collector(options);
6571
+ let order = 0;
6572
+ const listener = (...args) => {
6573
+ const item = args[0];
6574
+ const id = item?.id;
6575
+ const key = options.key?.(item) ?? (typeof id === "string" ? id : String(order++));
6576
+ collector.handle(key, item).catch((error) => this.emit("error" /* Error */, error instanceof Error ? error : new Error(String(error))));
6577
+ };
6578
+ this.on(event, listener);
6579
+ collector.onDispose(() => this.off(event, listener));
6580
+ return collector;
6581
+ }
6582
+ permissionsFor(memberId, guildOrChannelId) {
6583
+ let channel = this.channels.get(guildOrChannelId);
6584
+ if (channel?.isThread()) {
6585
+ channel = channel.parentId ? this.channels.get(channel.parentId) : undefined;
6586
+ if (!channel)
6587
+ return null;
6588
+ }
6589
+ const guildId = channel?.guildId ?? guildOrChannelId;
6590
+ const guild = this.guilds.get(guildId);
6591
+ const member = this.guilds.members(guildId).get(memberId);
6592
+ if (!guild || !member)
6593
+ return null;
6594
+ return computePermissions({
6595
+ guildId,
6596
+ ownerId: guild.ownerId,
6597
+ memberId,
6598
+ memberRoleIds: member.roleIds,
6599
+ roles: this.guilds.roles(guildId).values(),
6600
+ overwrites: channel?.permissionOverwrites
6601
+ });
6602
+ }
6603
+ fetchDefaultSoundboardSounds() {
6604
+ return this.rest.get(Routes.soundboardDefaultSounds());
6605
+ }
5459
6606
  async login(token) {
5460
6607
  if (this.state === "destroyed")
5461
6608
  throw new Error("Cannot login a destroyed client.");
@@ -5492,6 +6639,14 @@ class Client extends EventEmitter2 {
5492
6639
  return Promise.reject(new Error("Client is unauthenticated."));
5493
6640
  return this.rest.post(`/webhooks/${this.user.id}/${token}`, data);
5494
6641
  }
6642
+ interactionWebhookMessage(method, applicationId, token, messageId, data) {
6643
+ const path = messageId === "@original" ? Routes.interactionOriginalResponse(applicationId, token) : Routes.webhookMessage(applicationId, token, messageId);
6644
+ if (method === "GET")
6645
+ return this.rest.get(path);
6646
+ if (method === "PATCH")
6647
+ return this.rest.patch(path, data);
6648
+ return this.rest.delete(path);
6649
+ }
5495
6650
  fetchWebhook(id, token) {
5496
6651
  return this.rest.get(token ? `/webhooks/${id}/${token}` : `/webhooks/${id}`);
5497
6652
  }
@@ -5647,6 +6802,21 @@ class HandlerRegistry {
5647
6802
  return this.dispatch(event, ...args);
5648
6803
  }
5649
6804
  }
6805
+ // packages/sharding/package.json
6806
+ var package_default2 = {
6807
+ name: "@lunibee/sharding",
6808
+ version: "0.2.0",
6809
+ type: "module",
6810
+ module: "./src/index.ts",
6811
+ types: "./src/index.ts",
6812
+ exports: {
6813
+ ".": "./src/index.ts"
6814
+ },
6815
+ dependencies: {
6816
+ "@lunibee/ws": "workspace:*"
6817
+ }
6818
+ };
6819
+
5650
6820
  // packages/sharding/src/bus.ts
5651
6821
  var REPLY_TYPE = "__lunibee:reply";
5652
6822
 
@@ -5824,7 +6994,7 @@ class ClusterManager {
5824
6994
  const response = await fetch("https://discord.com/api/v10/gateway/bot", {
5825
6995
  headers: {
5826
6996
  Authorization: `Bot ${this.#options.token}`,
5827
- "User-Agent": "Lunibee/0.1.0"
6997
+ "User-Agent": `Lunibee/${package_default2.version}`
5828
6998
  }
5829
6999
  });
5830
7000
  if (!response.ok) {
@@ -5975,6 +7145,34 @@ class ClusterManager {
5975
7145
 
5976
7146
  // packages/sharding/src/index.ts
5977
7147
  var sleep3 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
7148
+ function needsConnection(gateway) {
7149
+ return gateway.state === "CONNECT" /* Connect */ || gateway.state === "RECONNECT" /* Reconnect */ || gateway.state === "CLOSED" /* Closed */;
7150
+ }
7151
+ var HANDSHAKE_SENT = new Set([
7152
+ "IDENTIFY" /* Identify */,
7153
+ "RESUME" /* Resume */,
7154
+ "READY" /* Ready */,
7155
+ "DISPATCH" /* Dispatch */,
7156
+ "HEARTBEAT" /* Heartbeat */,
7157
+ "CLOSED" /* Closed */
7158
+ ]);
7159
+ function handshakeSent(gateway, timeout) {
7160
+ if (HANDSHAKE_SENT.has(gateway.state))
7161
+ return Promise.resolve();
7162
+ return new Promise((resolve) => {
7163
+ const done = () => {
7164
+ clearTimeout(timer);
7165
+ gateway.off("stateChange", onState);
7166
+ resolve();
7167
+ };
7168
+ const onState = (change) => {
7169
+ if (HANDSHAKE_SENT.has(change.next))
7170
+ done();
7171
+ };
7172
+ const timer = setTimeout(done, timeout);
7173
+ gateway.on("stateChange", onState);
7174
+ });
7175
+ }
5978
7176
 
5979
7177
  class ShardManager {
5980
7178
  static IDENTIFY_INTERVAL = 5000;
@@ -5987,6 +7185,7 @@ class ShardManager {
5987
7185
  #destroyed = false;
5988
7186
  #auto;
5989
7187
  #autoScaleTimer;
7188
+ #gatewayInfo;
5990
7189
  constructor(options) {
5991
7190
  if (!options.token?.trim())
5992
7191
  throw new TypeError("A Discord bot token is required.");
@@ -5999,6 +7198,10 @@ class ShardManager {
5999
7198
  throw new RangeError("autoScaleInterval must be an integer of at least 1000 milliseconds.");
6000
7199
  if (options.spawnDelay !== undefined && (!Number.isFinite(options.spawnDelay) || options.spawnDelay < 0))
6001
7200
  throw new RangeError("spawnDelay must be a non-negative finite number of milliseconds.");
7201
+ if (options.maxConcurrency !== undefined && (!Number.isInteger(options.maxConcurrency) || options.maxConcurrency < 1))
7202
+ throw new RangeError("maxConcurrency must be a positive integer.");
7203
+ if (options.handshakeTimeout !== undefined && (!Number.isFinite(options.handshakeTimeout) || options.handshakeTimeout < 0))
7204
+ throw new RangeError("handshakeTimeout must be a non-negative number of milliseconds.");
6002
7205
  this.#auto = options.shardCount === "auto";
6003
7206
  this.#options = {
6004
7207
  spawnDelay: ShardManager.IDENTIFY_INTERVAL,
@@ -6008,10 +7211,13 @@ class ShardManager {
6008
7211
  this.#initialize(count);
6009
7212
  }
6010
7213
  async fetchRecommendedShardCount() {
7214
+ return (await this.fetchGatewayInfo()).shards;
7215
+ }
7216
+ async fetchGatewayInfo() {
6011
7217
  const response = await fetch("https://discord.com/api/v10/gateway/bot", {
6012
7218
  headers: {
6013
7219
  Authorization: `Bot ${this.#options.token}`,
6014
- "User-Agent": "Lunibee/0.1.0"
7220
+ "User-Agent": `Lunibee/${package_default2.version}`
6015
7221
  }
6016
7222
  });
6017
7223
  if (!response.ok)
@@ -6019,7 +7225,17 @@ class ShardManager {
6019
7225
  const data = await response.json();
6020
7226
  if (typeof data.shards !== "number" || !Number.isInteger(data.shards) || data.shards < 1)
6021
7227
  throw new Error("Gateway discovery returned an invalid shard count.");
6022
- return data.shards;
7228
+ const limit = data.session_start_limit;
7229
+ const info = { shards: data.shards };
7230
+ if (limit && typeof limit.total === "number" && typeof limit.remaining === "number" && typeof limit.reset_after === "number" && typeof limit.max_concurrency === "number")
7231
+ info.sessionStartLimit = {
7232
+ total: limit.total,
7233
+ remaining: limit.remaining,
7234
+ resetAfter: limit.reset_after,
7235
+ maxConcurrency: Math.max(1, limit.max_concurrency)
7236
+ };
7237
+ this.#gatewayInfo = info;
7238
+ return info;
6023
7239
  }
6024
7240
  async connect() {
6025
7241
  if (this.#autoScaleTimer) {
@@ -6027,17 +7243,25 @@ class ShardManager {
6027
7243
  this.#autoScaleTimer = undefined;
6028
7244
  }
6029
7245
  await this.#ensureInitialized();
6030
- for (const [id, shard] of this.shards) {
6031
- try {
6032
- await shard.connect();
6033
- } catch (error) {
7246
+ const limit = this.#gatewayInfo?.sessionStartLimit;
7247
+ const ids = [...this.shards].filter(([, gateway]) => needsConnection(gateway)).map(([id]) => id);
7248
+ if (limit && limit.remaining < ids.length)
7249
+ 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.`);
7250
+ const concurrency = Math.min(this.#options.maxConcurrency ?? limit?.maxConcurrency ?? 1, limit?.maxConcurrency ?? Infinity);
7251
+ for (let start = 0;start < ids.length; start += concurrency) {
7252
+ const round = ids.slice(start, start + concurrency);
7253
+ const results = await Promise.allSettled(round.map((id) => this.shards.get(id).connect()));
7254
+ const failed = results.findIndex((result) => result.status === "rejected");
7255
+ if (failed !== -1) {
6034
7256
  this.destroy();
6035
- throw new Error(`Failed to connect shard ${id}.`, {
6036
- cause: error
7257
+ throw new Error(`Failed to connect shard ${round[failed]}.`, {
7258
+ cause: results[failed].reason
6037
7259
  });
6038
7260
  }
6039
- if (id + 1 < this.shardCount && this.#options.spawnDelay && this.#options.spawnDelay > 0)
7261
+ if (start + concurrency < ids.length && this.#options.spawnDelay && this.#options.spawnDelay > 0) {
7262
+ await Promise.all(round.map((id) => handshakeSent(this.shards.get(id), this.#options.handshakeTimeout ?? 15000)));
6040
7263
  await sleep3(this.#options.spawnDelay);
7264
+ }
6041
7265
  }
6042
7266
  if (this.#options.autoScaleInterval && !this.#autoScaleTimer) {
6043
7267
  this.#autoScaleTimer = setInterval(() => {
@@ -6080,6 +7304,13 @@ class ShardManager {
6080
7304
  get(id) {
6081
7305
  return this.shards.get(id);
6082
7306
  }
7307
+ health() {
7308
+ return [...this.shards].map(([id, gateway]) => ({
7309
+ id,
7310
+ state: gateway.state,
7311
+ ping: gateway.ping
7312
+ }));
7313
+ }
6083
7314
  values() {
6084
7315
  return [...this.shards].map(([id, gateway]) => ({ id, gateway }));
6085
7316
  }
@@ -6203,12 +7434,14 @@ class VoiceConnection {
6203
7434
  if (this.state === "destroyed" /* Destroyed */)
6204
7435
  return;
6205
7436
  this.#closeTransports();
7437
+ this.receiver.close();
6206
7438
  this.#transition("disconnected" /* Disconnected */);
6207
7439
  }
6208
7440
  destroy() {
6209
7441
  if (this.state === "destroyed" /* Destroyed */)
6210
7442
  return;
6211
7443
  this.#closeTransports();
7444
+ this.receiver.close();
6212
7445
  this.channelId = undefined;
6213
7446
  this.#transition("destroyed" /* Destroyed */);
6214
7447
  this.#listeners.clear();
@@ -6416,6 +7649,8 @@ class VoiceReceiver {
6416
7649
  this.#ssrcMap.set(ssrc, userId);
6417
7650
  }
6418
7651
  subscribe(userId) {
7652
+ if (this.connection.state === "destroyed" /* Destroyed */)
7653
+ throw new VoiceError("Voice connection has been destroyed.");
6419
7654
  let controllerRef;
6420
7655
  const stream = new ReadableStream({
6421
7656
  start: (controller) => {
@@ -6436,6 +7671,16 @@ class VoiceReceiver {
6436
7671
  });
6437
7672
  return new AudioStream(stream, { title: `User ${userId} Audio` });
6438
7673
  }
7674
+ close() {
7675
+ for (const controllers of this.#streams.values())
7676
+ for (const controller of controllers) {
7677
+ try {
7678
+ controller.close();
7679
+ } catch {}
7680
+ }
7681
+ this.#streams.clear();
7682
+ this.#ssrcMap.clear();
7683
+ }
6439
7684
  onPacket(packet) {
6440
7685
  if (packet.length < 12)
6441
7686
  return;
@@ -6663,10 +7908,13 @@ class ActionRowBuilder {
6663
7908
  return this;
6664
7909
  }
6665
7910
  toJSON() {
6666
- return {
6667
- type: ComponentType.ActionRow,
6668
- components: this.#components.map((component) => component.toJSON())
6669
- };
7911
+ const components = this.#components.map((component) => component.toJSON());
7912
+ if (components.length === 0)
7913
+ throw new RangeError("An action row needs at least one component.");
7914
+ const types = components.map((component) => component.type);
7915
+ if (types.some((type) => type !== ComponentType.Button) && components.length > 1)
7916
+ throw new RangeError("A select menu or text input must be alone in its action row.");
7917
+ return { type: ComponentType.ActionRow, components };
6670
7918
  }
6671
7919
  }
6672
7920
 
@@ -6721,6 +7969,12 @@ class StringSelectBuilder {
6721
7969
  return this;
6722
7970
  }
6723
7971
  toJSON() {
7972
+ assertSelect(this.#data);
7973
+ const count = this.#data.options?.length ?? 0;
7974
+ if (count === 0)
7975
+ throw new RangeError("A string select needs at least one option.");
7976
+ if ((this.#data.max_values ?? 1) > count)
7977
+ throw new RangeError("max_values cannot exceed the number of options.");
6724
7978
  return structuredClone(this.#data);
6725
7979
  }
6726
7980
  }
@@ -6731,9 +7985,20 @@ class ButtonBuilder {
6731
7985
  style: ButtonStyle.Secondary
6732
7986
  };
6733
7987
  setStyle(style) {
6734
- this.#data.style = style;
6735
- if (style === ButtonStyle.Link)
6736
- delete this.#data.custom_id;
7988
+ const data = this.#data;
7989
+ data.style = style;
7990
+ if (style === ButtonStyle.Link) {
7991
+ delete data.custom_id;
7992
+ delete data.sku_id;
7993
+ } else if (style === ButtonStyle.Premium) {
7994
+ delete data.custom_id;
7995
+ delete data.url;
7996
+ delete data.label;
7997
+ delete data.emoji;
7998
+ } else {
7999
+ delete data.url;
8000
+ delete data.sku_id;
8001
+ }
6737
8002
  return this;
6738
8003
  }
6739
8004
  setCustomId(value) {
@@ -6758,11 +8023,16 @@ class ButtonBuilder {
6758
8023
  cause: error
6759
8024
  });
6760
8025
  }
6761
- this.#data.style = ButtonStyle.Link;
6762
- delete this.#data.custom_id;
8026
+ this.setStyle(ButtonStyle.Link);
6763
8027
  this.#data.url = url.toString();
6764
8028
  return this;
6765
8029
  }
8030
+ setSKUId(skuId) {
8031
+ validateText(skuId, 20, "Button SKU ID");
8032
+ this.setStyle(ButtonStyle.Premium);
8033
+ this.#data.sku_id = skuId;
8034
+ return this;
8035
+ }
6766
8036
  setEmoji(emoji) {
6767
8037
  this.#data.emoji = typeof emoji === "string" ? { name: emoji } : { ...emoji };
6768
8038
  return this;
@@ -6772,7 +8042,26 @@ class ButtonBuilder {
6772
8042
  return this;
6773
8043
  }
6774
8044
  toJSON() {
6775
- return structuredClone(this.#data);
8045
+ const data = this.#data;
8046
+ if (data.style === ButtonStyle.Link) {
8047
+ if (!data.url)
8048
+ throw new TypeError("Link buttons require a URL.");
8049
+ if (data.custom_id || data.sku_id)
8050
+ throw new TypeError("Link buttons cannot have a custom ID or SKU ID.");
8051
+ } else if (data.style === ButtonStyle.Premium) {
8052
+ if (!data.sku_id)
8053
+ throw new TypeError("Premium buttons require a SKU ID.");
8054
+ if (data.custom_id || data.url || data.label || data.emoji)
8055
+ throw new TypeError("Premium buttons cannot have a custom ID, URL, label or emoji.");
8056
+ } else {
8057
+ if (!data.custom_id)
8058
+ throw new TypeError("Non-link buttons require a custom ID.");
8059
+ if (data.url || data.sku_id)
8060
+ throw new TypeError("Only link buttons have a URL and only premium buttons have a SKU ID.");
8061
+ }
8062
+ if (data.style !== ButtonStyle.Premium && !data.label && !data.emoji)
8063
+ throw new TypeError("Buttons require a label or an emoji.");
8064
+ return structuredClone(data);
6776
8065
  }
6777
8066
  }
6778
8067
 
@@ -6816,6 +8105,7 @@ class EntitySelectBuilder {
6816
8105
  return this;
6817
8106
  }
6818
8107
  toJSON() {
8108
+ assertSelect(this.#data);
6819
8109
  return structuredClone(this.#data);
6820
8110
  }
6821
8111
  }
@@ -6843,6 +8133,10 @@ class ModalBuilder {
6843
8133
  return this;
6844
8134
  }
6845
8135
  toJSON() {
8136
+ if (!this.#custom_id || !this.#title)
8137
+ throw new TypeError("Modals require a custom ID and a title.");
8138
+ if (this.#components.length === 0)
8139
+ throw new RangeError("Modals require at least one component.");
6846
8140
  return {
6847
8141
  type: 9,
6848
8142
  ...this.#custom_id ? { custom_id: this.#custom_id } : {},
@@ -6896,7 +8190,12 @@ class TextInputBuilder {
6896
8190
  return this;
6897
8191
  }
6898
8192
  toJSON() {
6899
- return structuredClone(this.#data);
8193
+ const data = this.#data;
8194
+ if (!data.custom_id)
8195
+ throw new TypeError("Text inputs require a custom ID.");
8196
+ if (data.min_length !== undefined && data.max_length !== undefined && data.min_length > data.max_length)
8197
+ throw new RangeError("min_length cannot exceed max_length.");
8198
+ return structuredClone(data);
6900
8199
  }
6901
8200
  }
6902
8201
 
@@ -7123,6 +8422,12 @@ class ChannelSelectMenuBuilder extends EntitySelectBuilder {
7123
8422
  super(ComponentType.ChannelSelect);
7124
8423
  }
7125
8424
  }
8425
+ function assertSelect(data) {
8426
+ if (!data.custom_id)
8427
+ throw new TypeError("Select menus require a custom ID.");
8428
+ if ((data.min_values ?? 1) > (data.max_values ?? 1))
8429
+ throw new RangeError("min_values cannot exceed max_values.");
8430
+ }
7126
8431
  // packages/builders/src/commands.ts
7127
8432
  var ApplicationCommandOptionType2 = {
7128
8433
  Subcommand: 1,
@@ -7637,6 +8942,8 @@ export {
7637
8942
  GuildMemberManager,
7638
8943
  GuildOnboarding,
7639
8944
  GuildScheduledEventManager,
8945
+ GuildSoundboardManager,
8946
+ GuildStickerManager,
7640
8947
  GuildWelcomeScreen,
7641
8948
  HandlerRegistry,
7642
8949
  HttpTransport,
@@ -7662,6 +8969,7 @@ export {
7662
8969
  MessageManager,
7663
8970
  ModalBuilder,
7664
8971
  ModalSubmitInteraction,
8972
+ MonetizationManager,
7665
8973
  NewsChannel,
7666
8974
  NumberOptionBuilder,
7667
8975
  OnboardingPrompt,
@@ -7739,6 +9047,7 @@ export {
7739
9047
  classifyFrame,
7740
9048
  classifyPayload,
7741
9049
  codeBlock,
9050
+ computePermissions,
7742
9051
  createAudioPlayer,
7743
9052
  createAudioResource,
7744
9053
  createChannel,
@@ -7762,6 +9071,7 @@ export {
7762
9071
  normalizeRoutePath,
7763
9072
  orderedList,
7764
9073
  randomInt,
9074
+ redactPath,
7765
9075
  resolveGatewayIntents,
7766
9076
  resumePayload,
7767
9077
  roleMention,
@@ -7776,4 +9086,4 @@ export {
7776
9086
  userMention
7777
9087
  };
7778
9088
 
7779
- //# debugId=58F0E8EFC21C568E64756E2164756E21
9089
+ //# debugId=726AE42ABABEBEA864756E2164756E21