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
@@ -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) {
@@ -686,7 +804,340 @@ var InteractionResponseType = {
686
804
  Modal: 9
687
805
  };
688
806
  // packages/collection/src/index.ts
807
+ class RecencyList {
808
+ #nodes = new Map;
809
+ #oldest;
810
+ #newest;
811
+ get size() {
812
+ return this.#nodes.size;
813
+ }
814
+ oldest() {
815
+ return this.#oldest?.key;
816
+ }
817
+ touch(key) {
818
+ const node = this.#nodes.get(key);
819
+ if (node)
820
+ return this.#moveNewest(node);
821
+ const created = { key, older: this.#newest };
822
+ if (this.#newest)
823
+ this.#newest.newer = created;
824
+ else
825
+ this.#oldest = created;
826
+ this.#newest = created;
827
+ this.#nodes.set(key, created);
828
+ }
829
+ promote(key) {
830
+ const node = this.#nodes.get(key);
831
+ if (node)
832
+ this.#moveNewest(node);
833
+ }
834
+ delete(key) {
835
+ const node = this.#nodes.get(key);
836
+ if (!node)
837
+ return false;
838
+ this.#unlink(node);
839
+ this.#nodes.delete(key);
840
+ return true;
841
+ }
842
+ clear() {
843
+ this.#nodes.clear();
844
+ this.#oldest = this.#newest = undefined;
845
+ }
846
+ #unlink(node) {
847
+ if (node.older)
848
+ node.older.newer = node.newer;
849
+ else
850
+ this.#oldest = node.newer;
851
+ if (node.newer)
852
+ node.newer.older = node.older;
853
+ else
854
+ this.#newest = node.older;
855
+ node.older = node.newer = undefined;
856
+ }
857
+ #moveNewest(node) {
858
+ if (node === this.#newest)
859
+ return;
860
+ this.#unlink(node);
861
+ node.older = this.#newest;
862
+ if (this.#newest)
863
+ this.#newest.newer = node;
864
+ else
865
+ this.#oldest = node;
866
+ this.#newest = node;
867
+ }
868
+ }
869
+ function assertTTL(ttl) {
870
+ if (ttl !== undefined && (!Number.isFinite(ttl) || ttl <= 0))
871
+ throw new RangeError("TTL must be a positive number, or omitted.");
872
+ }
873
+
689
874
  class Collection extends Map {
875
+ #ttl;
876
+ #maxSize;
877
+ #onEvict;
878
+ #expiry = new Map;
879
+ #lru = new RecencyList;
880
+ #stats = {
881
+ hits: 0,
882
+ misses: 0,
883
+ expired: 0,
884
+ evicted: 0
885
+ };
886
+ #heap = [];
887
+ #timer;
888
+ #armedFor = Infinity;
889
+ constructor(entries, options = {}) {
890
+ super();
891
+ assertTTL(options.ttl);
892
+ if (options.maxSize !== undefined && (!Number.isInteger(options.maxSize) || options.maxSize <= 0))
893
+ throw new RangeError("maxSize must be a positive integer.");
894
+ this.#ttl = options.ttl;
895
+ this.#maxSize = options.maxSize;
896
+ this.#onEvict = options.onEvict;
897
+ if (entries)
898
+ for (const [key, value] of entries)
899
+ this.set(key, value);
900
+ }
901
+ set(key, value, ttl) {
902
+ assertTTL(ttl);
903
+ const window = ttl ?? this.#ttl;
904
+ if (this.#maxSize !== undefined) {
905
+ this.#lru.touch(key);
906
+ }
907
+ super.set(key, value);
908
+ if (window !== undefined)
909
+ this.#schedule(key, window);
910
+ else if (this.#expiry.size > 0)
911
+ this.#expiry.delete(key);
912
+ this.#enforceCap();
913
+ return this;
914
+ }
915
+ setWithoutTTL(key, value) {
916
+ if (this.#expiry.size > 0)
917
+ this.#expiry.delete(key);
918
+ if (this.#lru.size > 0)
919
+ this.#lru.delete(key);
920
+ super.set(key, value);
921
+ return this;
922
+ }
923
+ get(key) {
924
+ if (this.#expireIfDue(key)) {
925
+ this.#stats.misses++;
926
+ return;
927
+ }
928
+ const value = super.get(key);
929
+ if (value === undefined && !super.has(key)) {
930
+ this.#stats.misses++;
931
+ return;
932
+ }
933
+ this.#stats.hits++;
934
+ const expiry = this.#expiry.get(key);
935
+ if (expiry)
936
+ expiry.deadline = Date.now() + expiry.window;
937
+ this.#lru.promote(key);
938
+ return value;
939
+ }
940
+ peek(key) {
941
+ if (!this.#expireIfDue(key) && super.has(key)) {
942
+ this.#stats.hits++;
943
+ return super.get(key);
944
+ }
945
+ this.#stats.misses++;
946
+ return;
947
+ }
948
+ get stats() {
949
+ return { ...this.#stats };
950
+ }
951
+ has(key) {
952
+ return !this.#expireIfDue(key) && super.has(key);
953
+ }
954
+ delete(key) {
955
+ if (this.#expireIfDue(key))
956
+ return false;
957
+ this.#expiry.delete(key);
958
+ this.#lru.delete(key);
959
+ return super.delete(key);
960
+ }
961
+ clear() {
962
+ super.clear();
963
+ this.#expiry.clear();
964
+ this.#lru.clear();
965
+ this.#heap.length = 0;
966
+ if (this.#timer)
967
+ clearTimeout(this.#timer);
968
+ this.#timer = undefined;
969
+ this.#armedFor = Infinity;
970
+ }
971
+ get size() {
972
+ this.purge();
973
+ return super.size;
974
+ }
975
+ entries() {
976
+ this.purge();
977
+ return super.entries();
978
+ }
979
+ keys() {
980
+ this.purge();
981
+ return super.keys();
982
+ }
983
+ values() {
984
+ this.purge();
985
+ return super.values();
986
+ }
987
+ [Symbol.iterator]() {
988
+ return this.entries();
989
+ }
990
+ forEach(callback, thisArg) {
991
+ this.purge();
992
+ super.forEach(callback, thisArg);
993
+ }
994
+ ttlRemaining(key) {
995
+ if (this.#expireIfDue(key))
996
+ return;
997
+ const expiry = this.#expiry.get(key);
998
+ return expiry && Math.max(0, expiry.deadline - Date.now());
999
+ }
1000
+ purge() {
1001
+ if (this.#expiry.size === 0)
1002
+ return 0;
1003
+ const now = Date.now();
1004
+ let removed = 0;
1005
+ const dropped = [];
1006
+ while (this.#nextDeadline() <= now) {
1007
+ const due = this.#heapPop();
1008
+ dropped.push([due.key, super.get(due.key)]);
1009
+ this.#remove(due.key);
1010
+ removed++;
1011
+ }
1012
+ this.#stats.expired += removed;
1013
+ this.#rearm();
1014
+ for (const [key, value] of dropped)
1015
+ this.#notify(key, value, "expired");
1016
+ return removed;
1017
+ }
1018
+ #expireIfDue(key) {
1019
+ const expiry = this.#expiry.get(key);
1020
+ if (!expiry || expiry.deadline > Date.now())
1021
+ return false;
1022
+ const value = super.get(key);
1023
+ this.#remove(key);
1024
+ this.#stats.expired++;
1025
+ this.#notify(key, value, "expired");
1026
+ return true;
1027
+ }
1028
+ #remove(key) {
1029
+ this.#expiry.delete(key);
1030
+ this.#lru.delete(key);
1031
+ super.delete(key);
1032
+ }
1033
+ #notify(key, value, reason) {
1034
+ if (!this.#onEvict)
1035
+ return;
1036
+ try {
1037
+ this.#onEvict(key, value, reason);
1038
+ } catch {}
1039
+ }
1040
+ #enforceCap() {
1041
+ if (this.#maxSize === undefined)
1042
+ return;
1043
+ while (this.#lru.size > this.#maxSize) {
1044
+ const oldest = this.#lru.oldest();
1045
+ const value = super.get(oldest);
1046
+ this.#remove(oldest);
1047
+ this.#stats.evicted++;
1048
+ this.#notify(oldest, value, "evicted");
1049
+ }
1050
+ }
1051
+ #schedule(key, window) {
1052
+ const deadline = Date.now() + window;
1053
+ const expiry = this.#expiry.get(key);
1054
+ if (expiry) {
1055
+ expiry.deadline = deadline;
1056
+ expiry.window = window;
1057
+ if (deadline >= expiry.filed)
1058
+ return;
1059
+ expiry.filed = deadline;
1060
+ } else
1061
+ this.#expiry.set(key, { deadline, window, filed: deadline });
1062
+ this.#heapPush({ key, deadline });
1063
+ if (this.#heap.length > 2 * this.#expiry.size + 8)
1064
+ this.#compact();
1065
+ this.#rearm();
1066
+ }
1067
+ #nextDeadline() {
1068
+ for (;; ) {
1069
+ const top = this.#heap[0];
1070
+ if (top === undefined)
1071
+ return Infinity;
1072
+ const expiry = this.#expiry.get(top.key);
1073
+ if (!expiry || expiry.filed !== top.deadline) {
1074
+ this.#heapPop();
1075
+ continue;
1076
+ }
1077
+ if (expiry.deadline === top.deadline)
1078
+ return top.deadline;
1079
+ this.#heapPop();
1080
+ expiry.filed = expiry.deadline;
1081
+ this.#heapPush({ key: top.key, deadline: expiry.deadline });
1082
+ }
1083
+ }
1084
+ #compact() {
1085
+ const live = this.#heap.filter((record) => this.#expiry.get(record.key)?.filed === record.deadline);
1086
+ this.#heap.length = 0;
1087
+ for (const record of live)
1088
+ this.#heapPush(record);
1089
+ }
1090
+ #rearm() {
1091
+ const deadline = this.#nextDeadline();
1092
+ if (this.#timer !== undefined && deadline >= this.#armedFor)
1093
+ return;
1094
+ if (this.#timer)
1095
+ clearTimeout(this.#timer);
1096
+ this.#timer = undefined;
1097
+ this.#armedFor = deadline;
1098
+ if (deadline === Infinity)
1099
+ return;
1100
+ this.#timer = setTimeout(() => {
1101
+ this.#timer = undefined;
1102
+ this.#armedFor = Infinity;
1103
+ this.purge();
1104
+ }, Math.max(0, deadline - Date.now()));
1105
+ this.#timer.unref?.();
1106
+ }
1107
+ #heapPush(record) {
1108
+ const heap = this.#heap;
1109
+ heap.push(record);
1110
+ let i = heap.length - 1;
1111
+ while (i > 0) {
1112
+ const parent = i - 1 >> 1;
1113
+ if (heap[parent].deadline <= heap[i].deadline)
1114
+ break;
1115
+ [heap[parent], heap[i]] = [heap[i], heap[parent]];
1116
+ i = parent;
1117
+ }
1118
+ }
1119
+ #heapPop() {
1120
+ const heap = this.#heap;
1121
+ const top = heap[0];
1122
+ const last = heap.pop();
1123
+ if (top === undefined || heap.length === 0)
1124
+ return top;
1125
+ heap[0] = last;
1126
+ for (let i = 0;; ) {
1127
+ const left = 2 * i + 1;
1128
+ const right = left + 1;
1129
+ let smallest = i;
1130
+ if (left < heap.length && heap[left].deadline < heap[smallest].deadline)
1131
+ smallest = left;
1132
+ if (right < heap.length && heap[right].deadline < heap[smallest].deadline)
1133
+ smallest = right;
1134
+ if (smallest === i)
1135
+ break;
1136
+ [heap[smallest], heap[i]] = [heap[i], heap[smallest]];
1137
+ i = smallest;
1138
+ }
1139
+ return top;
1140
+ }
690
1141
  first() {
691
1142
  for (const value of this.values())
692
1143
  return value;
@@ -911,11 +1362,40 @@ class Manager {
911
1362
  has(id) {
912
1363
  return this.cache.has(id);
913
1364
  }
1365
+ #inflight = new Map;
1366
+ fetchOnce(id, load, store = (value) => {
1367
+ this.set(id, value);
1368
+ return value;
1369
+ }) {
1370
+ const pending = this.#inflight.get(id);
1371
+ if (pending)
1372
+ return pending.promise;
1373
+ const entry = {
1374
+ promise: new Promise((resolve) => resolve(load())),
1375
+ dirty: false
1376
+ };
1377
+ this.#inflight.set(id, entry);
1378
+ entry.promise = entry.promise.then((value) => {
1379
+ this.#inflight.delete(id);
1380
+ return entry.dirty ? this.get(id) ?? value : store(value);
1381
+ }, (error) => {
1382
+ this.#inflight.delete(id);
1383
+ throw error;
1384
+ });
1385
+ return entry.promise;
1386
+ }
1387
+ #markDirty(id) {
1388
+ const pending = this.#inflight.get(id);
1389
+ if (pending)
1390
+ pending.dirty = true;
1391
+ }
914
1392
  set(id, value) {
915
- this.cache.set(id, value);
1393
+ this.#markDirty(id);
1394
+ this.cache.setWithoutTTL(id, value);
916
1395
  return this;
917
1396
  }
918
1397
  delete(id) {
1398
+ this.#markDirty(id);
919
1399
  return this.cache.delete(id);
920
1400
  }
921
1401
  clear() {
@@ -951,16 +1431,20 @@ class ResourceManager extends Manager {
951
1431
  async resolve(id) {
952
1432
  return this.get(id) ?? this.fetch(id);
953
1433
  }
954
- async fetch(id) {
955
- const resource = await this.#fetcher(id);
956
- this.set(id, resource);
957
- return resource;
1434
+ fetch(id) {
1435
+ return this.fetchOnce(id, () => this.#fetcher(id));
958
1436
  }
959
1437
  async fetchMany(ids) {
960
1438
  return Promise.all([...ids].map((id) => this.resolve(id)));
961
1439
  }
962
1440
  upsert(resource) {
963
1441
  const key = this.#key(resource);
1442
+ const existing = this.get(key);
1443
+ if (existing !== undefined && existing !== resource && typeof existing === "object" && existing !== null) {
1444
+ Object.assign(existing, resource);
1445
+ this.set(key, existing);
1446
+ return existing;
1447
+ }
964
1448
  this.set(key, resource);
965
1449
  return resource;
966
1450
  }
@@ -971,7 +1455,7 @@ class ResourceManager extends Manager {
971
1455
  // packages/rest/package.json
972
1456
  var package_default = {
973
1457
  name: "@lunibee/rest",
974
- version: "0.1.8",
1458
+ version: "0.2.0",
975
1459
  type: "module",
976
1460
  module: "./src/index.ts",
977
1461
  types: "./src/index.ts",
@@ -1031,7 +1515,29 @@ class MemoryRateLimitStore {
1031
1515
  }
1032
1516
 
1033
1517
  // packages/rest/src/errors.ts
1518
+ function kindFromStatus(status) {
1519
+ if (status === 429)
1520
+ return "rateLimited";
1521
+ if (status === 401)
1522
+ return "authentication";
1523
+ if (status === 403)
1524
+ return "permission";
1525
+ if (status === 404)
1526
+ return "notFound";
1527
+ if (status === 400 || status === 422)
1528
+ return "validation";
1529
+ if (status >= 500)
1530
+ return "server";
1531
+ if (status === 0)
1532
+ return "network";
1533
+ return "client";
1534
+ }
1535
+ function redactPath(path) {
1536
+ return path.replace(/^(\/webhooks\/[^/?]+\/)[^/?]+/, "$1:token").replace(/^(\/interactions\/[^/?]+\/)[^/?]+/, "$1:token");
1537
+ }
1538
+
1034
1539
  class RESTError extends Error {
1540
+ kind;
1035
1541
  status;
1036
1542
  code;
1037
1543
  errors;
@@ -1041,14 +1547,18 @@ class RESTError extends Error {
1041
1547
  super(message, options.cause === undefined ? undefined : { cause: options.cause });
1042
1548
  this.name = "RESTError";
1043
1549
  this.status = status;
1550
+ this.kind = options.kind ?? kindFromStatus(status);
1044
1551
  this.code = code;
1045
1552
  this.errors = errors;
1046
1553
  this.method = options.method;
1047
- this.path = options.path;
1554
+ this.path = options.path === undefined ? undefined : redactPath(options.path);
1555
+ }
1556
+ get retryable() {
1557
+ return this.kind === "rateLimited" || this.kind === "server" || this.kind === "network" || this.kind === "timeout";
1048
1558
  }
1049
1559
  }
1050
1560
  function abortError(path, reason) {
1051
- return new RESTError(reason instanceof Error ? reason.message : "Discord REST request was aborted", 0, undefined, undefined, { path, cause: reason });
1561
+ return new RESTError(reason instanceof Error ? reason.message : "Discord REST request was aborted", 0, undefined, undefined, { path, cause: reason, kind: "aborted" });
1052
1562
  }
1053
1563
  async function sleep(delay, signal, path) {
1054
1564
  if (delay <= 0)
@@ -1383,8 +1893,23 @@ var Routes = {
1383
1893
  invite: (code) => `/invites/${encodeURIComponent(code)}`,
1384
1894
  guildVanity: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/vanity-url`,
1385
1895
  guildEmoji: (guildId, emojiId) => emojiId ? `/guilds/${snowflake(guildId, "Guild ID")}/emojis/${snowflake(emojiId, "Emoji ID")}` : `/guilds/${snowflake(guildId, "Guild ID")}/emojis`,
1386
- applicationEmoji: (applicationId, emojiId) => emojiId ? `/applications/${snowflake(applicationId, "Application ID")}/emojis/${snowflake(emojiId, "Emoji ID")}` : `/applications/${snowflake(applicationId, "Application ID")}/emojis`
1896
+ applicationEmoji: (applicationId, emojiId) => emojiId ? `/applications/${snowflake(applicationId, "Application ID")}/emojis/${snowflake(emojiId, "Emoji ID")}` : `/applications/${snowflake(applicationId, "Application ID")}/emojis`,
1897
+ pollExpire: (channelId, messageId) => `/channels/${snowflake(channelId, "Channel ID")}/polls/${snowflake(messageId, "Message ID")}/expire`,
1898
+ pollAnswerVoters: (channelId, messageId, answerId) => `/channels/${snowflake(channelId, "Channel ID")}/polls/${snowflake(messageId, "Message ID")}/answers/${integer(answerId, "Answer ID")}`,
1899
+ guildSticker: (guildId, stickerId) => stickerId ? `/guilds/${snowflake(guildId, "Guild ID")}/stickers/${snowflake(stickerId, "Sticker ID")}` : `/guilds/${snowflake(guildId, "Guild ID")}/stickers`,
1900
+ sendSoundboardSound: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/send-soundboard-sound`,
1901
+ soundboardDefaultSounds: () => "/soundboard-default-sounds",
1902
+ guildSoundboardSound: (guildId, soundId) => soundId ? `/guilds/${snowflake(guildId, "Guild ID")}/soundboard-sounds/${snowflake(soundId, "Sound ID")}` : `/guilds/${snowflake(guildId, "Guild ID")}/soundboard-sounds`,
1903
+ applicationSkus: (applicationId) => `/applications/${snowflake(applicationId, "Application ID")}/skus`,
1904
+ applicationEntitlement: (applicationId, entitlementId) => entitlementId ? `/applications/${snowflake(applicationId, "Application ID")}/entitlements/${snowflake(entitlementId, "Entitlement ID")}` : `/applications/${snowflake(applicationId, "Application ID")}/entitlements`,
1905
+ consumeEntitlement: (applicationId, entitlementId) => `/applications/${snowflake(applicationId, "Application ID")}/entitlements/${snowflake(entitlementId, "Entitlement ID")}/consume`,
1906
+ skuSubscription: (skuId, subscriptionId) => subscriptionId ? `/skus/${snowflake(skuId, "SKU ID")}/subscriptions/${snowflake(subscriptionId, "Subscription ID")}` : `/skus/${snowflake(skuId, "SKU ID")}/subscriptions`
1387
1907
  };
1908
+ function integer(value, field) {
1909
+ if (!Number.isInteger(value) || value < 0)
1910
+ throw new TypeError(`${field} must be a non-negative integer.`);
1911
+ return String(value);
1912
+ }
1388
1913
  function snowflake(value, field) {
1389
1914
  if (!/^\d{1,20}$/.test(value))
1390
1915
  throw new TypeError(`${field} must be a valid Discord snowflake.`);
@@ -1521,7 +2046,8 @@ class REST {
1521
2046
  throw new RESTError(failure.message, 0, undefined, undefined, {
1522
2047
  method,
1523
2048
  path,
1524
- cause: failure.cause ?? failure
2049
+ cause: failure.cause ?? failure,
2050
+ kind: failure.timedOut ? "timeout" : "network"
1525
2051
  });
1526
2052
  }
1527
2053
  this.#emit(this.#hooks.onResponse, {
@@ -1620,6 +2146,9 @@ class REST {
1620
2146
  #emit(hook, ctx) {
1621
2147
  if (!hook)
1622
2148
  return;
2149
+ const withPath = ctx;
2150
+ if (typeof withPath.path === "string")
2151
+ ctx = { ...ctx, path: redactPath(withPath.path) };
1623
2152
  Promise.resolve().then(() => hook(ctx)).catch(() => {});
1624
2153
  }
1625
2154
  }
@@ -1696,6 +2225,7 @@ class Channel extends BaseStructure {
1696
2225
  nsfw;
1697
2226
  rateLimitPerUser;
1698
2227
  position;
2228
+ permissionOverwrites;
1699
2229
  #context;
1700
2230
  constructor(data, context) {
1701
2231
  super(data.id);
@@ -1709,6 +2239,7 @@ class Channel extends BaseStructure {
1709
2239
  this.nsfw = data.nsfw;
1710
2240
  this.rateLimitPerUser = data.rate_limit_per_user;
1711
2241
  this.position = data.position;
2242
+ this.permissionOverwrites = (data.permission_overwrites ?? []).map((overwrite) => ({ ...overwrite }));
1712
2243
  this.#context = context;
1713
2244
  }
1714
2245
  sendMessage(options) {
@@ -1867,6 +2398,103 @@ class Guild extends BaseStructure {
1867
2398
  }
1868
2399
  }
1869
2400
  // packages/structures/src/resources.ts
2401
+ function toDateOrNull(value) {
2402
+ if (!value)
2403
+ return null;
2404
+ const date = new Date(value);
2405
+ return Number.isNaN(date.getTime()) ? null : date;
2406
+ }
2407
+
2408
+ class GuildMember {
2409
+ user;
2410
+ guildId;
2411
+ nickname;
2412
+ roleIds;
2413
+ pending;
2414
+ joinedAt;
2415
+ permissions;
2416
+ avatarHash;
2417
+ premiumSince;
2418
+ timedOutUntil;
2419
+ flags;
2420
+ constructor(data) {
2421
+ this.user = new User(data.user);
2422
+ if (!/^\d{1,20}$/.test(data.guild_id))
2423
+ throw new TypeError("Member guild_id must be a valid snowflake.");
2424
+ this.guildId = data.guild_id;
2425
+ this.nickname = data.nick ?? null;
2426
+ this.roleIds = [...data.roles ?? []];
2427
+ this.pending = data.pending ?? false;
2428
+ this.joinedAt = data.joined_at ? new Date(data.joined_at) : undefined;
2429
+ if (this.joinedAt?.toString() === "Invalid Date")
2430
+ throw new RangeError("Member joined_at must be a valid date.");
2431
+ this.permissions = new PermissionsBitField(data.permissions ?? 0n);
2432
+ this.avatarHash = data.avatar ?? null;
2433
+ this.premiumSince = toDateOrNull(data.premium_since);
2434
+ this.timedOutUntil = toDateOrNull(data.communication_disabled_until);
2435
+ this.flags = data.flags ?? 0;
2436
+ }
2437
+ get displayName() {
2438
+ return this.nickname ?? this.user.displayName;
2439
+ }
2440
+ get isTimedOut() {
2441
+ return this.timedOutUntil !== null && this.timedOutUntil > new Date;
2442
+ }
2443
+ avatarURL(options = {}) {
2444
+ if (this.avatarHash)
2445
+ return cdnURL(`/guilds/${this.guildId}/users/${this.user.id}/avatars`, this.avatarHash, options);
2446
+ return this.user.avatarURL(options);
2447
+ }
2448
+ displayAvatarURL(options = {}) {
2449
+ return this.avatarURL(options) ?? this.user.displayAvatarURL(options);
2450
+ }
2451
+ toString() {
2452
+ return this.user.toString();
2453
+ }
2454
+ }
2455
+
2456
+ class Role extends BaseStructure {
2457
+ name;
2458
+ color;
2459
+ hoist;
2460
+ permissions;
2461
+ managed;
2462
+ mentionable;
2463
+ position;
2464
+ unicodeEmoji;
2465
+ iconHash;
2466
+ tags;
2467
+ constructor(data) {
2468
+ super(data.id);
2469
+ if (!data.name)
2470
+ throw new TypeError("Role name cannot be empty.");
2471
+ this.name = data.name;
2472
+ this.color = data.color ?? 0;
2473
+ this.hoist = data.hoist ?? false;
2474
+ this.permissions = new PermissionsBitField(data.permissions ?? 0n);
2475
+ this.managed = data.managed ?? false;
2476
+ this.mentionable = data.mentionable ?? false;
2477
+ this.position = data.position ?? 0;
2478
+ this.unicodeEmoji = data.unicode_emoji ?? null;
2479
+ this.iconHash = data.icon ?? null;
2480
+ this.tags = data.tags ?? null;
2481
+ }
2482
+ get colorHex() {
2483
+ return `#${this.color.toString(16).padStart(6, "0").toUpperCase()}`;
2484
+ }
2485
+ iconURL(options = {}) {
2486
+ if (!this.iconHash)
2487
+ return null;
2488
+ return cdnURL(`/role-icons/${this.id}`, this.iconHash, options);
2489
+ }
2490
+ isEveryone(guildId) {
2491
+ return this.id === guildId;
2492
+ }
2493
+ toString() {
2494
+ return `<@&${this.id}>`;
2495
+ }
2496
+ }
2497
+
1870
2498
  class TextChannel extends Channel {
1871
2499
  constructor(data, context) {
1872
2500
  super(data, context);
@@ -1875,6 +2503,38 @@ class TextChannel extends Channel {
1875
2503
  return `<#${this.id}>`;
1876
2504
  }
1877
2505
  }
2506
+ class Emoji extends BaseStructure {
2507
+ name;
2508
+ roleIds;
2509
+ user;
2510
+ requireColons;
2511
+ managed;
2512
+ animated;
2513
+ available;
2514
+ constructor(data) {
2515
+ super(data.id ?? "0");
2516
+ if (data.id === null)
2517
+ this.id = "unicode";
2518
+ this.name = data.name;
2519
+ this.roleIds = data.roles ?? [];
2520
+ this.user = data.user ? new User(data.user) : null;
2521
+ this.requireColons = data.require_colons ?? false;
2522
+ this.managed = data.managed ?? false;
2523
+ this.animated = data.animated ?? false;
2524
+ this.available = data.available ?? true;
2525
+ }
2526
+ url(options = {}) {
2527
+ if (!this.id || this.id === "unicode")
2528
+ return null;
2529
+ const ext = options.extension ?? (this.animated ? "gif" : "png");
2530
+ const size = options.size ? `?size=${options.size}` : "";
2531
+ return `${CDN_BASE}/emojis/${this.id}.${ext}${size}`;
2532
+ }
2533
+ toString() {
2534
+ return this.id !== "unicode" ? `<${this.animated ? "a" : ""}:${this.name}:${this.id}>` : this.name ?? "";
2535
+ }
2536
+ }
2537
+
1878
2538
  class AutoModerationRule extends BaseStructure {
1879
2539
  guildId;
1880
2540
  name;
@@ -2192,6 +2852,17 @@ var InteractionType = {
2192
2852
  ApplicationCommandAutocomplete: 4,
2193
2853
  ModalSubmit: 5
2194
2854
  };
2855
+ var EPHEMERAL = 64;
2856
+ var TOKEN_LIFETIME_MS = 15 * 60000;
2857
+ var DISCORD_EPOCH = 1420070400000n;
2858
+ function toMessageData(options) {
2859
+ if (typeof options === "string")
2860
+ return { content: options };
2861
+ const { ephemeral, ...data } = options;
2862
+ if (ephemeral)
2863
+ data.flags = (typeof data.flags === "number" ? data.flags : 0) | EPHEMERAL;
2864
+ return data;
2865
+ }
2195
2866
 
2196
2867
  class InteractionResponse {
2197
2868
  type;
@@ -2206,14 +2877,10 @@ class InteractionResponse {
2206
2877
  return this.data === undefined ? { type: this.type } : { type: this.type, data: this.data };
2207
2878
  }
2208
2879
  static message(options) {
2209
- const data = { ...options };
2210
- if (options.ephemeral) {
2211
- data.flags = (typeof options.flags === "number" ? options.flags : 0) | 64;
2212
- }
2213
- return new InteractionResponse(InteractionResponseType.ChannelMessage, data);
2880
+ return new InteractionResponse(InteractionResponseType.ChannelMessage, toMessageData(options));
2214
2881
  }
2215
2882
  static defer(ephemeral = false) {
2216
- return new InteractionResponse(InteractionResponseType.DeferredChannelMessage, ephemeral ? { flags: 64 } : undefined);
2883
+ return new InteractionResponse(InteractionResponseType.DeferredChannelMessage, ephemeral ? { flags: EPHEMERAL } : undefined);
2217
2884
  }
2218
2885
  static pong() {
2219
2886
  return new InteractionResponse(InteractionResponseType.Pong);
@@ -2231,6 +2898,7 @@ class Interaction {
2231
2898
  replied = false;
2232
2899
  deferred = false;
2233
2900
  #client;
2901
+ #acknowledging = false;
2234
2902
  constructor(client, data) {
2235
2903
  if (!data.id || !data.token)
2236
2904
  throw new TypeError("Interaction ID and token are required.");
@@ -2280,9 +2948,57 @@ class Interaction {
2280
2948
  return [3, 5, 6, 7, 8].includes(this.#componentType());
2281
2949
  }
2282
2950
  assertUnacknowledged() {
2283
- if (this.replied || this.deferred)
2951
+ if (this.replied || this.deferred || this.#acknowledging)
2284
2952
  throw new Error("Interaction has already been acknowledged.");
2285
2953
  }
2954
+ async acknowledge(response, state) {
2955
+ this.assertUnacknowledged();
2956
+ this.#acknowledging = true;
2957
+ try {
2958
+ const result = await this.postResponse(response);
2959
+ this[state] = true;
2960
+ return result;
2961
+ } finally {
2962
+ this.#acknowledging = false;
2963
+ }
2964
+ }
2965
+ get user() {
2966
+ const raw = this.data.member?.user ?? this.data.user;
2967
+ return raw ? new User(raw) : null;
2968
+ }
2969
+ get member() {
2970
+ const raw = this.data.member;
2971
+ if (!raw || !this.guildId)
2972
+ return null;
2973
+ return new GuildMember({
2974
+ ...raw,
2975
+ guild_id: this.guildId
2976
+ });
2977
+ }
2978
+ get createdTimestamp() {
2979
+ return Number((BigInt(this.id) >> 22n) + DISCORD_EPOCH);
2980
+ }
2981
+ get expiresAt() {
2982
+ return new Date(this.createdTimestamp + TOKEN_LIFETIME_MS);
2983
+ }
2984
+ get isExpired() {
2985
+ return Date.now() >= this.createdTimestamp + TOKEN_LIFETIME_MS;
2986
+ }
2987
+ #webhookMessage(method, messageId, data) {
2988
+ if (!this.#client.interactionWebhookMessage)
2989
+ return Promise.reject(new Error("This interaction client does not support webhook message access."));
2990
+ return this.#client.interactionWebhookMessage(method, this.applicationId, this.token, messageId, data);
2991
+ }
2992
+ fetchReply() {
2993
+ this.assertAcknowledged();
2994
+ return this.#webhookMessage("GET", "@original");
2995
+ }
2996
+ editFollowUp(messageId, options) {
2997
+ return this.#webhookMessage("PATCH", messageId, toMessageData(options));
2998
+ }
2999
+ async deleteFollowUp(messageId) {
3000
+ await this.#webhookMessage("DELETE", messageId);
3001
+ }
2286
3002
  assertAcknowledged() {
2287
3003
  if (!this.replied && !this.deferred)
2288
3004
  throw new Error("Interaction has not been acknowledged.");
@@ -2291,41 +3007,27 @@ class Interaction {
2291
3007
  return this.#client.postInteractionResponse(this.id, this.token, response);
2292
3008
  }
2293
3009
  async reply(options) {
2294
- this.assertUnacknowledged();
2295
- const payload = typeof options === "string" ? { content: options } : options;
2296
- const result = await this.#client.postInteractionResponse(this.id, this.token, InteractionResponse.message(payload));
2297
- this.replied = true;
2298
- return result;
3010
+ return this.acknowledge(InteractionResponse.message(toMessageData(options)), "replied");
2299
3011
  }
2300
3012
  async deferReply(ephemeral = false) {
2301
- this.assertUnacknowledged();
2302
- await this.#client.postInteractionResponse(this.id, this.token, InteractionResponse.defer(ephemeral));
2303
- this.deferred = true;
3013
+ await this.acknowledge(InteractionResponse.defer(ephemeral), "deferred");
2304
3014
  }
2305
3015
  editReply(options) {
2306
3016
  this.assertAcknowledged();
2307
- return this.#client.editInteractionReply(this.token, options);
3017
+ return this.#client.editInteractionReply(this.token, toMessageData(options));
2308
3018
  }
2309
3019
  deleteReply() {
2310
3020
  this.assertAcknowledged();
2311
3021
  return this.#client.deleteInteractionReply(this.token);
2312
3022
  }
2313
3023
  followUp(options) {
2314
- const payload = typeof options === "string" ? { content: options } : options;
2315
- return this.#client.followUpInteraction(this.token, payload);
3024
+ return this.#client.followUpInteraction(this.token, toMessageData(options));
2316
3025
  }
2317
3026
  async update(options) {
2318
- this.assertUnacknowledged();
2319
- const payload = typeof options === "string" ? { content: options } : options;
2320
- const result = await this.#client.postInteractionResponse(this.id, this.token, new InteractionResponse(InteractionResponseType.MessageUpdate, payload));
2321
- this.replied = true;
2322
- return result;
3027
+ return this.acknowledge(new InteractionResponse(InteractionResponseType.MessageUpdate, toMessageData(options)), "replied");
2323
3028
  }
2324
3029
  async showModal(modal) {
2325
- this.assertUnacknowledged();
2326
- const result = await this.#client.postInteractionResponse(this.id, this.token, new InteractionResponse(InteractionResponseType.Modal, modal));
2327
- this.replied = true;
2328
- return result;
3030
+ return this.acknowledge(new InteractionResponse(InteractionResponseType.Modal, modal), "replied");
2329
3031
  }
2330
3032
  }
2331
3033
 
@@ -2353,16 +3055,10 @@ class ComponentInteraction extends Interaction {
2353
3055
  return this.data?.data?.values ?? [];
2354
3056
  }
2355
3057
  async deferUpdate() {
2356
- this.assertUnacknowledged();
2357
- await this.postResponse(new InteractionResponse(InteractionResponseType.DeferredMessageUpdate));
2358
- this.deferred = true;
3058
+ await this.acknowledge(new InteractionResponse(InteractionResponseType.DeferredMessageUpdate), "deferred");
2359
3059
  }
2360
3060
  async update(options) {
2361
- this.assertUnacknowledged();
2362
- const payload = typeof options === "string" ? { content: options } : options;
2363
- const result = await this.postResponse(new InteractionResponse(InteractionResponseType.MessageUpdate, payload));
2364
- this.replied = true;
2365
- return result;
3061
+ return this.acknowledge(new InteractionResponse(InteractionResponseType.MessageUpdate, toMessageData(options)), "replied");
2366
3062
  }
2367
3063
  }
2368
3064
 
@@ -2405,8 +3101,7 @@ class AutocompleteInteraction extends Interaction {
2405
3101
  if (!Array.isArray(choices))
2406
3102
  throw new TypeError("Autocomplete choices must be an array.");
2407
3103
  const response = new InteractionResponse(InteractionResponseType.Autocomplete, { choices });
2408
- await this.postResponse(response);
2409
- this.replied = true;
3104
+ await this.acknowledge(response, "replied");
2410
3105
  }
2411
3106
  }
2412
3107
  function findFocused(options) {
@@ -2593,16 +3288,22 @@ class Message extends BaseStructure {
2593
3288
 
2594
3289
  // packages/managers/src/message.ts
2595
3290
  class MessageManager {
2596
- cache = new Collection;
3291
+ cache;
3292
+ #caching;
2597
3293
  #rest;
2598
3294
  #context;
2599
3295
  #channelId;
2600
- constructor(rest, context, channelId) {
3296
+ constructor(rest, context, channelId, cache) {
2601
3297
  if (!channelId)
2602
3298
  throw new TypeError("Channel ID is required.");
2603
3299
  this.#rest = rest;
2604
3300
  this.#context = context;
2605
3301
  this.#channelId = channelId;
3302
+ this.#caching = cache !== undefined;
3303
+ this.cache = new Collection(null, {
3304
+ ttl: cache?.ttl,
3305
+ maxSize: cache ? cache.maxSize ?? 100 : undefined
3306
+ });
2606
3307
  }
2607
3308
  async resolve(messageId) {
2608
3309
  return this.cache.get(messageId) ?? this.fetch(messageId);
@@ -2619,13 +3320,14 @@ class MessageManager {
2619
3320
  return Promise.all(Array.from(messageIds, (messageId) => this.fetch(messageId)));
2620
3321
  }
2621
3322
  upsert(data) {
2622
- const existing = this.cache.get(data.id);
3323
+ const existing = this.cache.peek(data.id);
2623
3324
  const message = new Message(data, this.#context);
2624
3325
  if (existing) {
2625
3326
  Object.assign(existing, message);
2626
3327
  return existing;
2627
3328
  }
2628
- this.cache.set(message.id, message);
3329
+ if (this.#caching)
3330
+ this.cache.set(message.id, message);
2629
3331
  return message;
2630
3332
  }
2631
3333
  delete(messageId) {
@@ -2679,8 +3381,295 @@ class UserManager extends ResourceManager {
2679
3381
  });
2680
3382
  }
2681
3383
  }
3384
+ // packages/managers/src/emoji.ts
3385
+ class EmojiManager extends Manager {
3386
+ #rest;
3387
+ #guildId;
3388
+ constructor(rest, guildId) {
3389
+ super();
3390
+ this.#rest = rest;
3391
+ this.#guildId = guildId;
3392
+ }
3393
+ fetch(emojiId) {
3394
+ return this.fetchOnce(emojiId, async () => new Emoji(await this.#rest.get(Routes.guildEmoji(this.#guildId, emojiId))), (emoji) => this.#merge(emojiId, emoji));
3395
+ }
3396
+ async fetchAll() {
3397
+ const data = await this.#rest.get(Routes.guildEmoji(this.#guildId));
3398
+ return data.map((item) => this.upsert(item));
3399
+ }
3400
+ async create(options) {
3401
+ return this.upsert(await this.#rest.post(Routes.guildEmoji(this.#guildId), options));
3402
+ }
3403
+ async edit(emojiId, options) {
3404
+ return this.upsert(await this.#rest.patch(Routes.guildEmoji(this.#guildId, emojiId), options));
3405
+ }
3406
+ async deleteEmoji(emojiId) {
3407
+ await this.#rest.delete(Routes.guildEmoji(this.#guildId, emojiId));
3408
+ this.delete(emojiId);
3409
+ }
3410
+ upsert(data) {
3411
+ const key = data.id != null ? data.id : `unicode:${data.name ?? ""}`;
3412
+ return this.#merge(key, new Emoji(data));
3413
+ }
3414
+ #merge(key, emoji) {
3415
+ const existing = this.get(key);
3416
+ if (existing) {
3417
+ Object.assign(existing, emoji);
3418
+ return existing;
3419
+ }
3420
+ this.set(key, emoji);
3421
+ return emoji;
3422
+ }
3423
+ }
3424
+
3425
+ // packages/managers/src/advanced.ts
3426
+ function withQuery(path, query) {
3427
+ const params = new URLSearchParams;
3428
+ for (const [key, value] of Object.entries(query))
3429
+ if (value !== undefined)
3430
+ params.set(key, String(value));
3431
+ const suffix = params.toString();
3432
+ return suffix ? `${path}?${suffix}` : path;
3433
+ }
3434
+
3435
+ class GuildStickerManager extends Manager {
3436
+ #rest;
3437
+ guildId;
3438
+ constructor(rest, guildId) {
3439
+ super();
3440
+ this.#rest = rest;
3441
+ this.guildId = guildId;
3442
+ }
3443
+ #store(sticker) {
3444
+ this.set(sticker.id, sticker);
3445
+ return sticker;
3446
+ }
3447
+ async fetchAll() {
3448
+ const stickers = await this.#rest.get(Routes.guildSticker(this.guildId));
3449
+ this.clear();
3450
+ return stickers.map((sticker) => this.#store(sticker));
3451
+ }
3452
+ async fetch(stickerId) {
3453
+ return this.#store(await this.#rest.get(Routes.guildSticker(this.guildId, stickerId)));
3454
+ }
3455
+ async create(options) {
3456
+ const form = new FormData;
3457
+ form.set("name", options.name);
3458
+ form.set("description", options.description);
3459
+ form.set("tags", options.tags);
3460
+ form.set("file", options.file);
3461
+ return this.#store(await this.#rest.post(Routes.guildSticker(this.guildId), form, { reason: options.reason }));
3462
+ }
3463
+ async edit(stickerId, options) {
3464
+ const { reason, ...body } = options;
3465
+ return this.#store(await this.#rest.patch(Routes.guildSticker(this.guildId, stickerId), body, { reason }));
3466
+ }
3467
+ async remove(stickerId, reason) {
3468
+ await this.#rest.delete(Routes.guildSticker(this.guildId, stickerId), {
3469
+ reason
3470
+ });
3471
+ this.delete(stickerId);
3472
+ }
3473
+ sync(stickers) {
3474
+ this.clear();
3475
+ for (const sticker of stickers)
3476
+ this.#store(sticker);
3477
+ }
3478
+ }
3479
+
3480
+ class GuildSoundboardManager extends Manager {
3481
+ #rest;
3482
+ guildId;
3483
+ constructor(rest, guildId) {
3484
+ super();
3485
+ this.#rest = rest;
3486
+ this.guildId = guildId;
3487
+ }
3488
+ #store(sound) {
3489
+ this.set(sound.sound_id, sound);
3490
+ return sound;
3491
+ }
3492
+ async fetchAll() {
3493
+ const { items } = await this.#rest.get(Routes.guildSoundboardSound(this.guildId));
3494
+ this.clear();
3495
+ return items.map((sound) => this.#store(sound));
3496
+ }
3497
+ async fetch(soundId) {
3498
+ return this.#store(await this.#rest.get(Routes.guildSoundboardSound(this.guildId, soundId)));
3499
+ }
3500
+ async create(options) {
3501
+ if (options.volume !== undefined && (options.volume < 0 || options.volume > 1))
3502
+ throw new RangeError("Soundboard volume must be between 0 and 1.");
3503
+ return this.#store(await this.#rest.post(Routes.guildSoundboardSound(this.guildId), {
3504
+ name: options.name,
3505
+ sound: options.sound,
3506
+ volume: options.volume,
3507
+ emoji_id: options.emojiId,
3508
+ emoji_name: options.emojiName
3509
+ }, { reason: options.reason }));
3510
+ }
3511
+ async edit(soundId, options) {
3512
+ return this.#store(await this.#rest.patch(Routes.guildSoundboardSound(this.guildId, soundId), {
3513
+ name: options.name,
3514
+ volume: options.volume,
3515
+ emoji_id: options.emojiId,
3516
+ emoji_name: options.emojiName
3517
+ }, { reason: options.reason }));
3518
+ }
3519
+ async remove(soundId, reason) {
3520
+ await this.#rest.delete(Routes.guildSoundboardSound(this.guildId, soundId), { reason });
3521
+ this.delete(soundId);
3522
+ }
3523
+ }
3524
+
3525
+ class MonetizationManager extends Manager {
3526
+ #rest;
3527
+ applicationId;
3528
+ constructor(rest, applicationId) {
3529
+ super();
3530
+ this.#rest = rest;
3531
+ this.applicationId = applicationId;
3532
+ }
3533
+ fetchSkus() {
3534
+ return this.#rest.get(Routes.applicationSkus(this.applicationId));
3535
+ }
3536
+ async fetchEntitlements(query = {}) {
3537
+ if (query.limit !== undefined && (!Number.isInteger(query.limit) || query.limit < 1 || query.limit > 100))
3538
+ throw new RangeError("Entitlement limit must be 1-100.");
3539
+ const entitlements = await this.#rest.get(withQuery(Routes.applicationEntitlement(this.applicationId), {
3540
+ user_id: query.userId,
3541
+ sku_ids: query.skuIds?.join(","),
3542
+ guild_id: query.guildId,
3543
+ before: query.before,
3544
+ after: query.after,
3545
+ limit: query.limit,
3546
+ exclude_ended: query.excludeEnded,
3547
+ exclude_deleted: query.excludeDeleted
3548
+ }));
3549
+ for (const entitlement of entitlements)
3550
+ this.set(entitlement.id, entitlement);
3551
+ return entitlements;
3552
+ }
3553
+ async fetch(entitlementId) {
3554
+ const entitlement = await this.#rest.get(Routes.applicationEntitlement(this.applicationId, entitlementId));
3555
+ this.set(entitlement.id, entitlement);
3556
+ return entitlement;
3557
+ }
3558
+ async consume(entitlementId) {
3559
+ await this.#rest.post(Routes.consumeEntitlement(this.applicationId, entitlementId));
3560
+ const cached = this.get(entitlementId);
3561
+ if (cached)
3562
+ cached.consumed = true;
3563
+ }
3564
+ async createTestEntitlement(options) {
3565
+ const entitlement = await this.#rest.post(Routes.applicationEntitlement(this.applicationId), {
3566
+ sku_id: options.skuId,
3567
+ owner_id: options.ownerId,
3568
+ owner_type: options.ownerType
3569
+ });
3570
+ this.set(entitlement.id, entitlement);
3571
+ return entitlement;
3572
+ }
3573
+ async deleteTestEntitlement(entitlementId) {
3574
+ await this.#rest.delete(Routes.applicationEntitlement(this.applicationId, entitlementId));
3575
+ this.delete(entitlementId);
3576
+ }
3577
+ fetchSubscriptions(skuId, query = {}) {
3578
+ return this.#rest.get(withQuery(Routes.skuSubscription(skuId), {
3579
+ user_id: query.userId,
3580
+ before: query.before,
3581
+ after: query.after,
3582
+ limit: query.limit
3583
+ }));
3584
+ }
3585
+ fetchSubscription(skuId, subscriptionId) {
3586
+ return this.#rest.get(Routes.skuSubscription(skuId, subscriptionId));
3587
+ }
3588
+ }
3589
+
3590
+ // packages/managers/src/member.ts
3591
+ class GuildMemberManager extends ResourceManager {
3592
+ #rest;
3593
+ guildId;
3594
+ constructor(guildId, rest) {
3595
+ super((id) => rest.get(Routes.guildMember(guildId, id)).then((data) => new GuildMember({ ...data, guild_id: guildId })), (member) => member.user.id);
3596
+ this.guildId = guildId;
3597
+ this.#rest = rest;
3598
+ }
3599
+ async kick(userId) {
3600
+ await this.#rest.delete(Routes.guildMember(this.guildId, userId));
3601
+ this.delete(userId);
3602
+ }
3603
+ async ban(userId, options = {}) {
3604
+ await this.#rest.put(Routes.guildBan(this.guildId, userId), { delete_message_seconds: options.deleteMessageSeconds }, { reason: options.reason });
3605
+ this.delete(userId);
3606
+ }
3607
+ async unban(userId) {
3608
+ await this.#rest.delete(Routes.guildBan(this.guildId, userId));
3609
+ }
3610
+ async edit(userId, options) {
3611
+ const data = await this.#rest.patch(Routes.guildMember(this.guildId, userId), options);
3612
+ const member = new GuildMember({ ...data, guild_id: this.guildId });
3613
+ this.set(member.user.id, member);
3614
+ return member;
3615
+ }
3616
+ async addRole(userId, roleId) {
3617
+ await this.#rest.put(Routes.guildMemberRole(this.guildId, userId, roleId));
3618
+ }
3619
+ async removeRole(userId, roleId) {
3620
+ await this.#rest.delete(Routes.guildMemberRole(this.guildId, userId, roleId));
3621
+ }
3622
+ async timeout(userId, milliseconds) {
3623
+ const timeoutDate = milliseconds === null ? null : new Date(Date.now() + milliseconds).toISOString();
3624
+ return this.edit(userId, { communication_disabled_until: timeoutDate });
3625
+ }
3626
+ }
3627
+
3628
+ // packages/managers/src/role.ts
3629
+ class RoleManager extends ResourceManager {
3630
+ #rest;
3631
+ guildId;
3632
+ constructor(guildId, rest) {
3633
+ super((id) => rest.get(Routes.guildRole(guildId, id)).then((data) => new Role(data)), (role) => role.id);
3634
+ this.guildId = guildId;
3635
+ this.#rest = rest;
3636
+ }
3637
+ async fetchAll() {
3638
+ const data = await this.#rest.get(Routes.guildRoles(this.guildId));
3639
+ return data.map((item) => {
3640
+ const role = new Role(item);
3641
+ this.set(role.id, role);
3642
+ return role;
3643
+ });
3644
+ }
3645
+ async create(options) {
3646
+ const { reason, ...payload } = options;
3647
+ const data = await this.#rest.post(Routes.guildRoles(this.guildId), {
3648
+ ...payload,
3649
+ permissions: payload.permissions !== undefined ? String(payload.permissions) : undefined
3650
+ });
3651
+ const role = new Role(data);
3652
+ this.set(role.id, role);
3653
+ return role;
3654
+ }
3655
+ async edit(roleId, options) {
3656
+ const { reason, ...payload } = options;
3657
+ const data = await this.#rest.patch(Routes.guildRole(this.guildId, roleId), {
3658
+ ...payload,
3659
+ permissions: payload.permissions !== undefined ? String(payload.permissions) : undefined
3660
+ });
3661
+ const role = new Role(data);
3662
+ this.set(role.id, role);
3663
+ return role;
3664
+ }
3665
+ async deleteRole(roleId) {
3666
+ await this.#rest.delete(Routes.guildRole(this.guildId, roleId));
3667
+ this.delete(roleId);
3668
+ }
3669
+ }
3670
+
2682
3671
  // packages/managers/src/guild-resources.ts
2683
- function withQuery(path, params) {
3672
+ function withQuery2(path, params) {
2684
3673
  const query = new URLSearchParams;
2685
3674
  for (const [key, value] of Object.entries(params))
2686
3675
  if (value !== undefined)
@@ -2704,7 +3693,7 @@ class GuildBanManager extends Manager {
2704
3693
  }
2705
3694
  async fetchAll(options = {}) {
2706
3695
  const limit = options.limit === undefined ? undefined : Math.min(1000, Math.max(1, options.limit));
2707
- const bans = await this.#rest.get(withQuery(Routes.guildBans(this.guildId), {
3696
+ const bans = await this.#rest.get(withQuery2(Routes.guildBans(this.guildId), {
2708
3697
  limit,
2709
3698
  before: options.before,
2710
3699
  after: options.after
@@ -2737,12 +3726,12 @@ class GuildScheduledEventManager extends Manager {
2737
3726
  return event;
2738
3727
  }
2739
3728
  async fetch(eventId, options = {}) {
2740
- return this.#store(await this.#rest.get(withQuery(Routes.guildScheduledEvent(this.guildId, eventId), {
3729
+ return this.#store(await this.#rest.get(withQuery2(Routes.guildScheduledEvent(this.guildId, eventId), {
2741
3730
  with_user_count: options.withUserCount
2742
3731
  })));
2743
3732
  }
2744
3733
  async fetchAll(options = {}) {
2745
- const events = await this.#rest.get(withQuery(Routes.guildScheduledEvents(this.guildId), {
3734
+ const events = await this.#rest.get(withQuery2(Routes.guildScheduledEvents(this.guildId), {
2746
3735
  with_user_count: options.withUserCount
2747
3736
  }));
2748
3737
  return events.map((event) => this.#store(event));
@@ -2759,7 +3748,7 @@ class GuildScheduledEventManager extends Manager {
2759
3748
  }
2760
3749
  async fetchSubscribers(eventId, options = {}) {
2761
3750
  const limit = options.limit === undefined ? undefined : Math.min(100, Math.max(1, options.limit));
2762
- return this.#rest.get(withQuery(Routes.guildScheduledEventUsers(this.guildId, eventId), {
3751
+ return this.#rest.get(withQuery2(Routes.guildScheduledEventUsers(this.guildId, eventId), {
2763
3752
  limit,
2764
3753
  with_member: options.withMember,
2765
3754
  before: options.before,
@@ -2821,7 +3810,7 @@ class PermissionOverwriteManager {
2821
3810
  }
2822
3811
 
2823
3812
  // packages/managers/src/guild.ts
2824
- function withQuery2(path, params) {
3813
+ function withQuery3(path, params) {
2825
3814
  const suffix = params.toString();
2826
3815
  return suffix ? `${path}?${suffix}` : path;
2827
3816
  }
@@ -2830,6 +3819,20 @@ class GuildManager extends ResourceManager {
2830
3819
  #rest;
2831
3820
  #bans = new Map;
2832
3821
  #scheduledEvents = new Map;
3822
+ #members = new Map;
3823
+ #roles = new Map;
3824
+ #emojis = new Map;
3825
+ #stickers = new Map;
3826
+ #soundboard = new Map;
3827
+ #voiceStates = new Map;
3828
+ #autoModerationRules = new Map;
3829
+ #invites = new Map;
3830
+ #perGuild(map, guildId, create) {
3831
+ let manager = map.get(guildId);
3832
+ if (!manager)
3833
+ map.set(guildId, manager = create());
3834
+ return manager;
3835
+ }
2833
3836
  constructor(rest) {
2834
3837
  super(async (id) => new Guild(await rest.get(Routes.guild(id))), (guild) => guild.id);
2835
3838
  this.#rest = rest;
@@ -2846,6 +3849,68 @@ class GuildManager extends ResourceManager {
2846
3849
  this.#scheduledEvents.set(guildId, manager = new GuildScheduledEventManager(this.#rest, guildId));
2847
3850
  return manager;
2848
3851
  }
3852
+ members(guildId) {
3853
+ let manager = this.#members.get(guildId);
3854
+ if (!manager)
3855
+ this.#members.set(guildId, manager = new GuildMemberManager(guildId, this.#rest));
3856
+ return manager;
3857
+ }
3858
+ roles(guildId) {
3859
+ let manager = this.#roles.get(guildId);
3860
+ if (!manager)
3861
+ this.#roles.set(guildId, manager = new RoleManager(guildId, this.#rest));
3862
+ return manager;
3863
+ }
3864
+ emojis(guildId) {
3865
+ let manager = this.#emojis.get(guildId);
3866
+ if (!manager)
3867
+ this.#emojis.set(guildId, manager = new EmojiManager(this.#rest, guildId));
3868
+ return manager;
3869
+ }
3870
+ stickers(guildId) {
3871
+ let manager = this.#stickers.get(guildId);
3872
+ if (!manager)
3873
+ this.#stickers.set(guildId, manager = new GuildStickerManager(this.#rest, guildId));
3874
+ return manager;
3875
+ }
3876
+ soundboard(guildId) {
3877
+ let manager = this.#soundboard.get(guildId);
3878
+ if (!manager)
3879
+ this.#soundboard.set(guildId, manager = new GuildSoundboardManager(this.#rest, guildId));
3880
+ return manager;
3881
+ }
3882
+ voiceStates(guildId) {
3883
+ return this.#perGuild(this.#voiceStates, guildId, () => new Manager);
3884
+ }
3885
+ autoModerationRules(guildId) {
3886
+ return this.#perGuild(this.#autoModerationRules, guildId, () => new Manager);
3887
+ }
3888
+ invites(guildId) {
3889
+ return this.#perGuild(this.#invites, guildId, () => new Manager);
3890
+ }
3891
+ patch(data) {
3892
+ const guild = new Guild(data);
3893
+ const existing = this.get(guild.id);
3894
+ if (!existing)
3895
+ return this.upsert(guild);
3896
+ for (const [key, value] of Object.entries(guild))
3897
+ if (value !== undefined)
3898
+ existing[key] = value;
3899
+ return existing;
3900
+ }
3901
+ delete(id) {
3902
+ this.#bans.delete(id);
3903
+ this.#scheduledEvents.delete(id);
3904
+ this.#members.delete(id);
3905
+ this.#roles.delete(id);
3906
+ this.#emojis.delete(id);
3907
+ this.#stickers.delete(id);
3908
+ this.#soundboard.delete(id);
3909
+ this.#voiceStates.delete(id);
3910
+ this.#autoModerationRules.delete(id);
3911
+ this.#invites.delete(id);
3912
+ return super.delete(id);
3913
+ }
2849
3914
  async create(options) {
2850
3915
  const data = await this.#rest.post("/guilds", options);
2851
3916
  return this.upsert(new Guild(data));
@@ -2881,7 +3946,7 @@ class GuildManager extends ResourceManager {
2881
3946
  params.set("after", options.after);
2882
3947
  if (options.limit !== undefined)
2883
3948
  params.set("limit", String(Math.min(100, Math.max(1, options.limit))));
2884
- return this.#rest.get(withQuery2(Routes.guildAuditLog(guildId), params));
3949
+ return this.#rest.get(withQuery3(Routes.guildAuditLog(guildId), params));
2885
3950
  }
2886
3951
  async fetchMembers(guildId, options = {}) {
2887
3952
  const params = new URLSearchParams;
@@ -2889,7 +3954,7 @@ class GuildManager extends ResourceManager {
2889
3954
  params.set("limit", String(Math.min(1000, Math.max(1, options.limit))));
2890
3955
  if (options.after)
2891
3956
  params.set("after", options.after);
2892
- return this.#rest.get(withQuery2(Routes.guildMembers(guildId), params));
3957
+ return this.#rest.get(withQuery3(Routes.guildMembers(guildId), params));
2893
3958
  }
2894
3959
  async fetchAutoModerationRules(guildId) {
2895
3960
  const rules = await this.#rest.get(Routes.guildAutoModerationRules(guildId));
@@ -2952,13 +4017,20 @@ class ApplicationCommandManager {
2952
4017
  }
2953
4018
 
2954
4019
  // packages/managers/src/index.ts
4020
+ var BULK_DELETE_MAX_AGE_MS = 14 * 24 * 60 * 60000;
4021
+ function snowflakeTime(id) {
4022
+ return Number((BigInt(id) >> 22n) + 1420070400000n);
4023
+ }
4024
+
2955
4025
  class ChannelManager extends Manager {
2956
4026
  #rest;
2957
4027
  #context;
2958
4028
  #messageManagers = new Map;
2959
- constructor(rest) {
4029
+ #messageCache;
4030
+ constructor(rest, options = {}) {
2960
4031
  super();
2961
4032
  this.#rest = rest;
4033
+ this.#messageCache = options.messageCache;
2962
4034
  this.#context = {
2963
4035
  sendMessage: (channelId, options) => this.send(channelId, options),
2964
4036
  editMessage: (channelId, messageId, options) => this.editMessage(channelId, messageId, options),
@@ -2977,7 +4049,7 @@ class ChannelManager extends Manager {
2977
4049
  messages(channelId) {
2978
4050
  let manager = this.#messageManagers.get(channelId);
2979
4051
  if (!manager) {
2980
- manager = new MessageManager(this.#rest, this.#context, channelId);
4052
+ manager = new MessageManager(this.#rest, this.#context, channelId, this.#messageCache);
2981
4053
  this.#messageManagers.set(channelId, manager);
2982
4054
  }
2983
4055
  return manager;
@@ -2988,16 +4060,18 @@ class ChannelManager extends Manager {
2988
4060
  threads(channelId) {
2989
4061
  return new ThreadManager(this.#rest, this.#context, channelId);
2990
4062
  }
2991
- async fetch(channelId) {
2992
- return this.upsert(await this.#rest.get(Routes.channel(channelId)));
4063
+ fetch(channelId) {
4064
+ return this.fetchOnce(channelId, async () => createChannel(await this.#rest.get(Routes.channel(channelId)), this.#context), (channel) => this.#merge(channel));
2993
4065
  }
2994
4066
  async resolve(channelId) {
2995
4067
  return this.get(channelId) ?? this.fetch(channelId);
2996
4068
  }
2997
4069
  upsert(data) {
2998
- const existing = this.get(data.id);
2999
- const channel = createChannel(data, this.#context);
3000
- if (existing) {
4070
+ return this.#merge(createChannel(data, this.#context));
4071
+ }
4072
+ #merge(channel) {
4073
+ const existing = this.get(channel.id);
4074
+ if (existing && existing.type === channel.type) {
3001
4075
  Object.assign(existing, channel);
3002
4076
  return existing;
3003
4077
  }
@@ -3007,6 +4081,37 @@ class ChannelManager extends Manager {
3007
4081
  update(channel) {
3008
4082
  return this.set(channel.id, channel);
3009
4083
  }
4084
+ deleteGuildChannels(guildId) {
4085
+ let removed = 0;
4086
+ for (const channel of this.values())
4087
+ if (channel.guildId === guildId && this.delete(channel.id))
4088
+ removed++;
4089
+ return removed;
4090
+ }
4091
+ async endPoll(channelId, messageId) {
4092
+ return this.messages(channelId).upsert(await this.#rest.post(Routes.pollExpire(channelId, messageId)));
4093
+ }
4094
+ async fetchPollVoters(channelId, messageId, answerId, options = {}) {
4095
+ if (options.limit !== undefined && (!Number.isInteger(options.limit) || options.limit < 1 || options.limit > 100))
4096
+ throw new RangeError("Poll voter limit must be 1-100.");
4097
+ const params = new URLSearchParams;
4098
+ if (options.after)
4099
+ params.set("after", options.after);
4100
+ if (options.limit !== undefined)
4101
+ params.set("limit", String(options.limit));
4102
+ const suffix = params.toString();
4103
+ const { users } = await this.#rest.get(`${Routes.pollAnswerVoters(channelId, messageId, answerId)}${suffix ? `?${suffix}` : ""}`);
4104
+ return users.map((user) => new User(user));
4105
+ }
4106
+ async sendSoundboardSound(channelId, options) {
4107
+ await this.#rest.post(Routes.sendSoundboardSound(channelId), {
4108
+ sound_id: options.soundId,
4109
+ source_guild_id: options.sourceGuildId
4110
+ });
4111
+ }
4112
+ cachedMessages(channelId) {
4113
+ return this.#messageManagers.get(channelId);
4114
+ }
3010
4115
  async create(guildId, options) {
3011
4116
  return this.upsert(await this.#rest.post(Routes.guildChannels(guildId), options));
3012
4117
  }
@@ -3063,15 +4168,37 @@ class ChannelManager extends Manager {
3063
4168
  return this.messages(channelId).upsert(await this.#rest.post(Routes.crosspostMessage(channelId, messageId)));
3064
4169
  }
3065
4170
  async bulkDeleteMessages(channelId, messageIds) {
3066
- const ids = [...messageIds];
3067
- if (ids.length < 2 || ids.length > 100)
3068
- throw new RangeError("bulkDelete requires between 2 and 100 message IDs.");
4171
+ const ids = [...new Set(messageIds)];
4172
+ if (ids.length < 1 || ids.length > 100)
4173
+ throw new RangeError("bulkDelete requires between 1 and 100 message IDs.");
4174
+ if (ids.length === 1)
4175
+ return this.deleteMessage(channelId, ids[0]);
4176
+ const cutoff = Date.now() - BULK_DELETE_MAX_AGE_MS;
4177
+ const tooOld = ids.filter((id) => snowflakeTime(id) < cutoff);
4178
+ if (tooOld.length)
4179
+ throw new RangeError(`bulkDelete cannot delete messages older than 14 days: ${tooOld.join(", ")}`);
3069
4180
  await this.#rest.post(Routes.channelBulkDelete(channelId), {
3070
4181
  messages: ids
3071
4182
  });
3072
4183
  for (const id of ids)
3073
4184
  this.messages(channelId).delete(id);
3074
4185
  }
4186
+ async* iterateMessages(channelId, options = {}) {
4187
+ let before = options.before;
4188
+ let remaining = options.limit ?? Infinity;
4189
+ while (remaining > 0) {
4190
+ const page = await this.fetchMessages(channelId, {
4191
+ before,
4192
+ limit: Math.min(100, remaining)
4193
+ });
4194
+ for (const message of page)
4195
+ yield message;
4196
+ remaining -= page.length;
4197
+ if (page.length < 100)
4198
+ return;
4199
+ before = page.at(-1).id;
4200
+ }
4201
+ }
3075
4202
  async addReaction(channelId, messageId, emoji) {
3076
4203
  await this.#rest.put(`${Routes.messageReactions(channelId, messageId, emoji)}/@me`);
3077
4204
  }
@@ -3167,6 +4294,8 @@ class GatewaySession {
3167
4294
  return false;
3168
4295
  if (!Number.isInteger(sequence))
3169
4296
  return false;
4297
+ if (this.#sequence !== null && sequence < this.#sequence)
4298
+ return false;
3170
4299
  this.#sequence = sequence;
3171
4300
  return true;
3172
4301
  }
@@ -3265,8 +4394,11 @@ class GatewayHeartbeat {
3265
4394
  this.#clearBeatTimers();
3266
4395
  this.#interval = interval;
3267
4396
  this.#acknowledged = true;
3268
- this.#initialTimer = setTimeout(() => this.sendHeartbeat(), Math.random() * interval);
3269
- this.#timer = setInterval(() => this.sendHeartbeat(), interval);
4397
+ this.#initialTimer = setTimeout(() => {
4398
+ this.#initialTimer = undefined;
4399
+ this.sendHeartbeat();
4400
+ this.#timer = setInterval(() => this.sendHeartbeat(), interval);
4401
+ }, Math.random() * interval);
3270
4402
  }
3271
4403
  stop() {
3272
4404
  this.#clearBeatTimers();
@@ -3292,6 +4424,8 @@ class GatewayHeartbeat {
3292
4424
  }, this.#options.ackTimeout);
3293
4425
  }
3294
4426
  acknowledge() {
4427
+ if (this.#acknowledged)
4428
+ return;
3295
4429
  this.#acknowledged = true;
3296
4430
  this.#latency = this.#now() - this.#sentAt;
3297
4431
  this.#clearAckTimer();
@@ -3860,6 +4994,7 @@ class SendBudget {
3860
4994
  }
3861
4995
 
3862
4996
  // packages/ws/src/index.ts
4997
+ var RESUMABLE_CLOSE_CODE = 4900;
3863
4998
  var DEFAULT_GATEWAY_URL = "wss://gateway.discord.gg/?v=10&encoding=json";
3864
4999
 
3865
5000
  class Gateway {
@@ -3945,7 +5080,7 @@ class Gateway {
3945
5080
  } else {
3946
5081
  this.#emitError(new GatewayError(`Gateway heartbeat acknowledgement timed out after ${timeout.elapsedMs}ms.`));
3947
5082
  }
3948
- this.#transport.close(1001, timeout.type === "zombie" ? "Zombie Gateway connection" : "Heartbeat timeout");
5083
+ this.#transport.close(RESUMABLE_CLOSE_CODE, timeout.type === "zombie" ? "Zombie Gateway connection" : "Heartbeat timeout");
3949
5084
  }
3950
5085
  connect(url = DEFAULT_GATEWAY_URL) {
3951
5086
  if (this.state === "CLOSED" /* Closed */)
@@ -4081,7 +5216,7 @@ class Gateway {
4081
5216
  this.#emit("heartbeatAck", action.data);
4082
5217
  return;
4083
5218
  case "reconnect":
4084
- this.#transport.close(1001, "Server requested reconnect");
5219
+ this.#transport.close(RESUMABLE_CLOSE_CODE, "Server requested reconnect");
4085
5220
  return;
4086
5221
  case "invalid-session": {
4087
5222
  if (!action.resumable)
@@ -4275,6 +5410,7 @@ class Client extends EventEmitter2 {
4275
5410
  channels;
4276
5411
  stageInstances;
4277
5412
  application;
5413
+ monetization;
4278
5414
  get ws() {
4279
5415
  return this.#gateway;
4280
5416
  }
@@ -4306,6 +5442,7 @@ class Client extends EventEmitter2 {
4306
5442
  return this.#gateway.requestGuildMembers(data);
4307
5443
  }
4308
5444
  #gateway;
5445
+ #cache;
4309
5446
  #resourceContext;
4310
5447
  constructor(options) {
4311
5448
  super();
@@ -4313,9 +5450,18 @@ class Client extends EventEmitter2 {
4313
5450
  if (!options.token?.trim())
4314
5451
  throw new TypeError("Client token is required.");
4315
5452
  this.rest = new REST({ token: options.token, ...options.rest });
5453
+ this.#cache = {
5454
+ users: true,
5455
+ members: true,
5456
+ roles: true,
5457
+ emojis: true,
5458
+ ...options.cache
5459
+ };
4316
5460
  this.users = new UserManager(this.rest);
4317
5461
  this.guilds = new GuildManager(this.rest);
4318
- this.channels = new ChannelManager(this.rest);
5462
+ this.channels = new ChannelManager(this.rest, {
5463
+ messageCache: options.messageCache
5464
+ });
4319
5465
  this.stageInstances = new StageInstanceManager(this.rest);
4320
5466
  const placeholderAppCommands = new ApplicationCommandManager(this.rest, "0");
4321
5467
  this.application = { commands: placeholderAppCommands };
@@ -4346,6 +5492,8 @@ class Client extends EventEmitter2 {
4346
5492
  this.state = "ready";
4347
5493
  const appId = ready.application?.id ?? this.user.id;
4348
5494
  this.application.commands = new ApplicationCommandManager(this.rest, appId);
5495
+ if (this.monetization?.applicationId !== appId)
5496
+ this.monetization = new MonetizationManager(this.rest, appId);
4349
5497
  this.emit("ready" /* Ready */, this.user);
4350
5498
  });
4351
5499
  this.#gateway.on("RESUMED", () => {
@@ -4363,18 +5511,39 @@ class Client extends EventEmitter2 {
4363
5511
  });
4364
5512
  this.#gateway.on("MESSAGE_CREATE", (data) => {
4365
5513
  const message = new Message(data, this.#resourceContext);
4366
- this.channels.set(message.channelId, message.channel);
4367
- this.users.set(message.author.id, message.author);
4368
- this.emit("messageCreate" /* MessageCreate */, message);
5514
+ this.#observeMessage(message);
5515
+ const cached = this.options.messageCache ? this.channels.messages(message.channelId).upsert(data) : message;
5516
+ this.emit("messageCreate" /* MessageCreate */, cached);
4369
5517
  });
4370
5518
  this.#gateway.on("MESSAGE_UPDATE", (data) => {
4371
5519
  const message = new Message(data, this.#resourceContext);
4372
- this.channels.set(message.channelId, message.channel);
4373
- this.users.set(message.author.id, message.author);
4374
- this.emit("messageUpdate" /* MessageUpdate */, message);
5520
+ this.#observeMessage(message);
5521
+ const messages = this.channels.cachedMessages(message.channelId);
5522
+ const previous = messages?.cache.peek(message.id);
5523
+ if (previous)
5524
+ messages.cache.set(message.id, message);
5525
+ this.emit("messageUpdate" /* MessageUpdate */, message, previous);
5526
+ });
5527
+ this.#gateway.on("MESSAGE_DELETE", (data) => {
5528
+ const payload = data;
5529
+ const messages = this.channels.cachedMessages(payload.channel_id);
5530
+ const removed = messages?.cache.peek(payload.id);
5531
+ messages?.delete(payload.id);
5532
+ this.emit("messageDelete" /* MessageDelete */, payload, removed);
5533
+ });
5534
+ this.#gateway.on("MESSAGE_DELETE_BULK", (data) => {
5535
+ const payload = data;
5536
+ const messages = this.channels.cachedMessages(payload.channel_id);
5537
+ const removed = [];
5538
+ if (messages)
5539
+ for (const id of payload.ids) {
5540
+ const message = messages.cache.peek(id);
5541
+ if (message)
5542
+ removed.push(message);
5543
+ messages.delete(id);
5544
+ }
5545
+ this.emit("messageDeleteBulk" /* MessageDeleteBulk */, payload, removed);
4375
5546
  });
4376
- this.#gateway.on("MESSAGE_DELETE", (data) => this.emit("messageDelete" /* MessageDelete */, data));
4377
- this.#gateway.on("MESSAGE_DELETE_BULK", (data) => this.emit("messageDeleteBulk" /* MessageDeleteBulk */, data));
4378
5547
  this.#gateway.on("MESSAGE_REACTION_ADD", (data) => this.emit("messageReactionAdd" /* MessageReactionAdd */, data));
4379
5548
  this.#gateway.on("MESSAGE_REACTION_REMOVE", (data) => this.emit("messageReactionRemove" /* MessageReactionRemove */, data));
4380
5549
  this.#gateway.on("MESSAGE_REACTION_REMOVE_ALL", (data) => this.emit("messageReactionRemoveAll" /* MessageReactionRemoveAll */, data));
@@ -4388,20 +5557,27 @@ class Client extends EventEmitter2 {
4388
5557
  return;
4389
5558
  }
4390
5559
  const wasCached = this.guilds.has(payload.id);
4391
- const guild = new Guild(payload);
4392
- this.guilds.set(guild.id, guild);
5560
+ this.guilds.patch(payload);
5561
+ for (const role of payload.roles ?? [])
5562
+ this.#upsertRole(payload.id, role);
5563
+ if (this.#cache.emojis) {
5564
+ const emojis = this.guilds.emojis(payload.id);
5565
+ for (const emoji of payload.emojis ?? [])
5566
+ emojis.upsert(emoji);
5567
+ }
4393
5568
  for (const member of payload.members ?? [])
4394
- this.users.set(member.user.id, new User(member.user));
5569
+ this.#upsertMember(payload.id, member);
5570
+ for (const state of payload.voice_states ?? [])
5571
+ this.#storeVoiceState(payload.id, state);
4395
5572
  for (const channelData of [
4396
5573
  ...payload.channels ?? [],
4397
5574
  ...payload.threads ?? []
4398
5575
  ])
4399
- this.channels.set(channelData.id, createChannel(channelData, this.#resourceContext));
5576
+ this.channels.upsert({ ...channelData, guild_id: payload.id });
4400
5577
  this.emit(wasCached ? "guildAvailable" /* GuildAvailable */ : "guildCreate" /* GuildCreate */, payload);
4401
5578
  });
4402
5579
  this.#gateway.on("GUILD_UPDATE", (data) => {
4403
- const guild = new Guild(data);
4404
- this.guilds.update(guild);
5580
+ this.guilds.patch(data);
4405
5581
  this.emit("guildUpdate" /* GuildUpdate */, data);
4406
5582
  });
4407
5583
  this.#gateway.on("GUILD_DELETE", (data) => {
@@ -4411,45 +5587,158 @@ class Client extends EventEmitter2 {
4411
5587
  return;
4412
5588
  }
4413
5589
  this.guilds.delete(payload.id);
5590
+ this.channels.deleteGuildChannels(payload.id);
4414
5591
  this.emit("guildDelete" /* GuildDelete */, payload);
4415
5592
  });
4416
5593
  this.#gateway.on("GUILD_MEMBER_ADD", (data) => {
4417
5594
  const member = data;
4418
- this.users.set(member.user.id, new User(member.user));
5595
+ this.#upsertMember(member.guild_id, member);
4419
5596
  this.emit("guildMemberAdd" /* GuildMemberAdd */, member);
4420
5597
  });
4421
5598
  this.#gateway.on("GUILD_MEMBER_UPDATE", (data) => {
4422
5599
  const member = data;
4423
- this.users.set(member.user.id, new User(member.user));
5600
+ this.#upsertMember(member.guild_id, member);
4424
5601
  this.emit("guildMemberUpdate" /* GuildMemberUpdate */, member);
4425
5602
  });
4426
- this.#gateway.on("GUILD_MEMBER_REMOVE", (data) => this.emit("guildMemberRemove" /* GuildMemberRemove */, data));
4427
- this.#gateway.on("GUILD_MEMBERS_CHUNK", (data) => this.emit("guildMembersChunk" /* GuildMembersChunk */, data));
4428
- this.#gateway.on("GUILD_BAN_ADD", (data) => this.emit("guildBanAdd" /* GuildBanAdd */, data));
4429
- this.#gateway.on("GUILD_BAN_REMOVE", (data) => this.emit("guildBanRemove" /* GuildBanRemove */, data));
4430
- this.#gateway.on("GUILD_ROLE_CREATE", (data) => this.emit("guildRoleCreate" /* GuildRoleCreate */, data));
4431
- this.#gateway.on("GUILD_ROLE_UPDATE", (data) => this.emit("guildRoleUpdate" /* GuildRoleUpdate */, data));
4432
- this.#gateway.on("GUILD_ROLE_DELETE", (data) => this.emit("guildRoleDelete" /* GuildRoleDelete */, data));
4433
- this.#gateway.on("GUILD_EMOJIS_UPDATE", (data) => this.emit("guildEmojisUpdate" /* GuildEmojisUpdate */, data));
4434
- this.#gateway.on("GUILD_STICKERS_UPDATE", (data) => this.emit("guildStickersUpdate" /* GuildStickersUpdate */, data));
5603
+ this.#gateway.on("GUILD_MEMBER_REMOVE", (data) => {
5604
+ const member = data;
5605
+ this.guilds.members(member.guild_id).delete(member.user.id);
5606
+ this.emit("guildMemberRemove" /* GuildMemberRemove */, member);
5607
+ });
5608
+ this.#gateway.on("GUILD_MEMBERS_CHUNK", (data) => {
5609
+ const chunk = data;
5610
+ for (const member of chunk.members)
5611
+ this.#upsertMember(chunk.guild_id, member);
5612
+ this.emit("guildMembersChunk" /* GuildMembersChunk */, chunk);
5613
+ });
5614
+ this.#gateway.on("GUILD_BAN_ADD", (data) => {
5615
+ const ban = data;
5616
+ const bans = this.guilds.bans(ban.guild_id);
5617
+ bans.set(ban.user.id, {
5618
+ reason: bans.get(ban.user.id)?.reason ?? null,
5619
+ user: ban.user
5620
+ });
5621
+ this.guilds.members(ban.guild_id).delete(ban.user.id);
5622
+ this.emit("guildBanAdd" /* GuildBanAdd */, ban);
5623
+ });
5624
+ this.#gateway.on("GUILD_BAN_REMOVE", (data) => {
5625
+ const ban = data;
5626
+ this.guilds.bans(ban.guild_id).delete(ban.user.id);
5627
+ this.emit("guildBanRemove" /* GuildBanRemove */, ban);
5628
+ });
5629
+ this.#gateway.on("GUILD_ROLE_CREATE", (data) => {
5630
+ const event = data;
5631
+ this.#upsertRole(event.guild_id, event.role);
5632
+ this.emit("guildRoleCreate" /* GuildRoleCreate */, event);
5633
+ });
5634
+ this.#gateway.on("GUILD_ROLE_UPDATE", (data) => {
5635
+ const event = data;
5636
+ this.#upsertRole(event.guild_id, event.role);
5637
+ this.emit("guildRoleUpdate" /* GuildRoleUpdate */, event);
5638
+ });
5639
+ this.#gateway.on("GUILD_ROLE_DELETE", (data) => {
5640
+ const event = data;
5641
+ this.guilds.roles(event.guild_id).delete(event.role_id);
5642
+ this.emit("guildRoleDelete" /* GuildRoleDelete */, event);
5643
+ });
5644
+ this.#gateway.on("GUILD_EMOJIS_UPDATE", (data) => {
5645
+ const event = data;
5646
+ if (this.#cache.emojis) {
5647
+ const emojis = this.guilds.emojis(event.guild_id);
5648
+ const current = new Set(event.emojis.map((emoji) => emoji.id));
5649
+ for (const id of [...emojis.cache.keys()])
5650
+ if (!current.has(id))
5651
+ emojis.delete(id);
5652
+ for (const emoji of event.emojis)
5653
+ emojis.upsert(emoji);
5654
+ }
5655
+ this.emit("guildEmojisUpdate" /* GuildEmojisUpdate */, event);
5656
+ });
5657
+ this.#gateway.on("GUILD_STICKERS_UPDATE", (data) => {
5658
+ const event = data;
5659
+ this.guilds.stickers(event.guild_id).sync(event.stickers);
5660
+ this.emit("guildStickersUpdate" /* GuildStickersUpdate */, event);
5661
+ });
5662
+ this.#gateway.on("GUILD_SOUNDBOARD_SOUND_CREATE", (data) => {
5663
+ const sound = data;
5664
+ if (sound.guild_id)
5665
+ this.guilds.soundboard(sound.guild_id).set(sound.sound_id, sound);
5666
+ this.emit("soundboardSoundCreate" /* SoundboardSoundCreate */, sound);
5667
+ });
5668
+ this.#gateway.on("GUILD_SOUNDBOARD_SOUND_UPDATE", (data) => {
5669
+ const sound = data;
5670
+ if (sound.guild_id)
5671
+ this.guilds.soundboard(sound.guild_id).set(sound.sound_id, sound);
5672
+ this.emit("soundboardSoundUpdate" /* SoundboardSoundUpdate */, sound);
5673
+ });
5674
+ this.#gateway.on("GUILD_SOUNDBOARD_SOUND_DELETE", (data) => {
5675
+ const event = data;
5676
+ this.guilds.soundboard(event.guild_id).delete(event.sound_id);
5677
+ this.emit("soundboardSoundDelete" /* SoundboardSoundDelete */, event);
5678
+ });
5679
+ this.#gateway.on("GUILD_SOUNDBOARD_SOUNDS_UPDATE", (data) => {
5680
+ const event = data;
5681
+ const sounds = this.guilds.soundboard(event.guild_id);
5682
+ sounds.clear();
5683
+ for (const sound of event.soundboard_sounds)
5684
+ sounds.set(sound.sound_id, sound);
5685
+ this.emit("soundboardSoundsUpdate" /* SoundboardSoundsUpdate */, event);
5686
+ });
5687
+ this.#gateway.on("ENTITLEMENT_CREATE", (data) => {
5688
+ const entitlement = data;
5689
+ this.monetization?.set(entitlement.id, entitlement);
5690
+ this.emit("entitlementCreate" /* EntitlementCreate */, entitlement);
5691
+ });
5692
+ this.#gateway.on("ENTITLEMENT_UPDATE", (data) => {
5693
+ const entitlement = data;
5694
+ this.monetization?.set(entitlement.id, entitlement);
5695
+ this.emit("entitlementUpdate" /* EntitlementUpdate */, entitlement);
5696
+ });
5697
+ this.#gateway.on("ENTITLEMENT_DELETE", (data) => {
5698
+ const entitlement = data;
5699
+ this.monetization?.delete(entitlement.id);
5700
+ this.emit("entitlementDelete" /* EntitlementDelete */, entitlement);
5701
+ });
4435
5702
  this.#gateway.on("GUILD_INTEGRATIONS_UPDATE", (data) => this.emit("guildIntegrationsUpdate" /* GuildIntegrationsUpdate */, data));
4436
- this.#gateway.on("GUILD_SCHEDULED_EVENT_CREATE", (data) => this.emit("guildScheduledEventCreate" /* GuildScheduledEventCreate */, data));
4437
- this.#gateway.on("GUILD_SCHEDULED_EVENT_UPDATE", (data) => this.emit("guildScheduledEventUpdate" /* GuildScheduledEventUpdate */, data));
4438
- this.#gateway.on("GUILD_SCHEDULED_EVENT_DELETE", (data) => this.emit("guildScheduledEventDelete" /* GuildScheduledEventDelete */, data));
5703
+ this.#gateway.on("GUILD_SCHEDULED_EVENT_CREATE", (data) => {
5704
+ const event = data;
5705
+ this.guilds.scheduledEvents(event.guild_id).set(event.id, event);
5706
+ this.emit("guildScheduledEventCreate" /* GuildScheduledEventCreate */, event);
5707
+ });
5708
+ this.#gateway.on("GUILD_SCHEDULED_EVENT_UPDATE", (data) => {
5709
+ const event = data;
5710
+ this.guilds.scheduledEvents(event.guild_id).set(event.id, event);
5711
+ this.emit("guildScheduledEventUpdate" /* GuildScheduledEventUpdate */, event);
5712
+ });
5713
+ this.#gateway.on("GUILD_SCHEDULED_EVENT_DELETE", (data) => {
5714
+ const event = data;
5715
+ this.guilds.scheduledEvents(event.guild_id).delete(event.id);
5716
+ this.emit("guildScheduledEventDelete" /* GuildScheduledEventDelete */, event);
5717
+ });
4439
5718
  this.#gateway.on("GUILD_SCHEDULED_EVENT_USER_ADD", (data) => this.emit("guildScheduledEventUserAdd" /* GuildScheduledEventUserAdd */, data));
4440
5719
  this.#gateway.on("GUILD_SCHEDULED_EVENT_USER_REMOVE", (data) => this.emit("guildScheduledEventUserRemove" /* GuildScheduledEventUserRemove */, data));
4441
- this.#gateway.on("AUTO_MODERATION_RULE_CREATE", (data) => this.emit("autoModerationRuleCreate" /* AutoModerationRuleCreate */, data));
4442
- this.#gateway.on("AUTO_MODERATION_RULE_UPDATE", (data) => this.emit("autoModerationRuleUpdate" /* AutoModerationRuleUpdate */, data));
4443
- this.#gateway.on("AUTO_MODERATION_RULE_DELETE", (data) => this.emit("autoModerationRuleDelete" /* AutoModerationRuleDelete */, data));
5720
+ this.#gateway.on("AUTO_MODERATION_RULE_CREATE", (data) => {
5721
+ const rule = data;
5722
+ this.guilds.autoModerationRules(rule.guild_id).set(rule.id, rule);
5723
+ this.emit("autoModerationRuleCreate" /* AutoModerationRuleCreate */, rule);
5724
+ });
5725
+ this.#gateway.on("AUTO_MODERATION_RULE_UPDATE", (data) => {
5726
+ const rule = data;
5727
+ this.guilds.autoModerationRules(rule.guild_id).set(rule.id, rule);
5728
+ this.emit("autoModerationRuleUpdate" /* AutoModerationRuleUpdate */, rule);
5729
+ });
5730
+ this.#gateway.on("AUTO_MODERATION_RULE_DELETE", (data) => {
5731
+ const rule = data;
5732
+ this.guilds.autoModerationRules(rule.guild_id).delete(rule.id);
5733
+ this.emit("autoModerationRuleDelete" /* AutoModerationRuleDelete */, rule);
5734
+ });
4444
5735
  this.#gateway.on("AUTO_MODERATION_ACTION_EXECUTION", (data) => this.emit("autoModerationActionExecution" /* AutoModerationActionExecution */, data));
4445
5736
  this.#gateway.on("CHANNEL_CREATE", (data) => {
4446
- const channel = createChannel(data, this.#resourceContext);
4447
- this.channels.update(channel);
5737
+ const channel = this.channels.upsert(data);
4448
5738
  this.emit("channelCreate" /* ChannelCreate */, channel);
4449
5739
  });
4450
5740
  this.#gateway.on("CHANNEL_UPDATE", (data) => {
4451
- const channel = createChannel(data, this.#resourceContext);
4452
- this.channels.update(channel);
5741
+ const channel = this.channels.upsert(data);
4453
5742
  this.emit("channelUpdate" /* ChannelUpdate */, channel);
4454
5743
  });
4455
5744
  this.#gateway.on("CHANNEL_DELETE", (data) => {
@@ -4459,13 +5748,11 @@ class Client extends EventEmitter2 {
4459
5748
  });
4460
5749
  this.#gateway.on("CHANNEL_PINS_UPDATE", (data) => this.emit("channelPinsUpdate" /* ChannelPinsUpdate */, data));
4461
5750
  this.#gateway.on("THREAD_CREATE", (data) => {
4462
- const channel = createChannel(data, this.#resourceContext);
4463
- this.channels.update(channel);
5751
+ const channel = this.channels.upsert(data);
4464
5752
  this.emit("threadCreate" /* ThreadCreate */, channel);
4465
5753
  });
4466
5754
  this.#gateway.on("THREAD_UPDATE", (data) => {
4467
- const channel = createChannel(data, this.#resourceContext);
4468
- this.channels.update(channel);
5755
+ const channel = this.channels.upsert(data);
4469
5756
  this.emit("threadUpdate" /* ThreadUpdate */, channel);
4470
5757
  });
4471
5758
  this.#gateway.on("THREAD_DELETE", (data) => {
@@ -4473,16 +5760,48 @@ class Client extends EventEmitter2 {
4473
5760
  this.channels.delete(payload.id);
4474
5761
  this.emit("threadDelete" /* ThreadDelete */, payload);
4475
5762
  });
4476
- this.#gateway.on("THREAD_LIST_SYNC", (data) => this.emit("threadListSync" /* ThreadListSync */, data));
5763
+ this.#gateway.on("THREAD_LIST_SYNC", (data) => {
5764
+ const sync = data;
5765
+ for (const thread of sync.threads)
5766
+ this.channels.upsert({ ...thread, guild_id: sync.guild_id });
5767
+ this.emit("threadListSync" /* ThreadListSync */, sync);
5768
+ });
4477
5769
  this.#gateway.on("THREAD_MEMBERS_UPDATE", (data) => this.emit("threadMembersUpdate" /* ThreadMembersUpdate */, data));
4478
5770
  this.#gateway.on("THREAD_MEMBER_UPDATE", (data) => this.emit("threadMemberUpdate" /* ThreadMemberUpdate */, data));
4479
- this.#gateway.on("STAGE_INSTANCE_CREATE", (data) => this.emit("stageInstanceCreate" /* StageInstanceCreate */, data));
4480
- this.#gateway.on("STAGE_INSTANCE_UPDATE", (data) => this.emit("stageInstanceUpdate" /* StageInstanceUpdate */, data));
4481
- this.#gateway.on("STAGE_INSTANCE_DELETE", (data) => this.emit("stageInstanceDelete" /* StageInstanceDelete */, data));
4482
- this.#gateway.on("INVITE_CREATE", (data) => this.emit("inviteCreate" /* InviteCreate */, data));
4483
- this.#gateway.on("INVITE_DELETE", (data) => this.emit("inviteDelete" /* InviteDelete */, data));
5771
+ this.#gateway.on("STAGE_INSTANCE_CREATE", (data) => {
5772
+ const stage = data;
5773
+ this.stageInstances.set(stage.channel_id, stage);
5774
+ this.emit("stageInstanceCreate" /* StageInstanceCreate */, stage);
5775
+ });
5776
+ this.#gateway.on("STAGE_INSTANCE_UPDATE", (data) => {
5777
+ const stage = data;
5778
+ this.stageInstances.set(stage.channel_id, stage);
5779
+ this.emit("stageInstanceUpdate" /* StageInstanceUpdate */, stage);
5780
+ });
5781
+ this.#gateway.on("STAGE_INSTANCE_DELETE", (data) => {
5782
+ const stage = data;
5783
+ this.stageInstances.delete(stage.channel_id);
5784
+ this.emit("stageInstanceDelete" /* StageInstanceDelete */, stage);
5785
+ });
5786
+ this.#gateway.on("INVITE_CREATE", (data) => {
5787
+ const invite = data;
5788
+ if (invite.guild_id)
5789
+ this.guilds.invites(invite.guild_id).set(invite.code, invite);
5790
+ this.emit("inviteCreate" /* InviteCreate */, invite);
5791
+ });
5792
+ this.#gateway.on("INVITE_DELETE", (data) => {
5793
+ const invite = data;
5794
+ if (invite.guild_id)
5795
+ this.guilds.invites(invite.guild_id).delete(invite.code);
5796
+ this.emit("inviteDelete" /* InviteDelete */, invite);
5797
+ });
4484
5798
  this.#gateway.on("WEBHOOKS_UPDATE", (data) => this.emit("webhooksUpdate" /* WebhooksUpdate */, data));
4485
- this.#gateway.on("VOICE_STATE_UPDATE", (data) => this.emit("voiceStateUpdate" /* VoiceStateUpdate */, data));
5799
+ this.#gateway.on("VOICE_STATE_UPDATE", (data) => {
5800
+ const state = data;
5801
+ if (state.guild_id)
5802
+ this.#storeVoiceState(state.guild_id, state);
5803
+ this.emit("voiceStateUpdate" /* VoiceStateUpdate */, state);
5804
+ });
4486
5805
  this.#gateway.on("VOICE_SERVER_UPDATE", (data) => this.emit("voiceServerUpdate" /* VoiceServerUpdate */, data));
4487
5806
  this.#gateway.on("PRESENCE_UPDATE", (data) => this.emit("presenceUpdate" /* PresenceUpdate */, data));
4488
5807
  this.#gateway.on("TYPING_START", (data) => this.emit("typingStart" /* TypingStart */, data));
@@ -4490,6 +5809,80 @@ class Client extends EventEmitter2 {
4490
5809
  this.#gateway.on("RAW", (data) => this.emit("raw" /* Raw */, data));
4491
5810
  this.#gateway.on("error", (error) => this.emit("error" /* Error */, error));
4492
5811
  }
5812
+ #observeMessage(message) {
5813
+ if (!this.channels.has(message.channelId))
5814
+ this.channels.set(message.channelId, message.channel);
5815
+ if (this.#cache.users)
5816
+ this.#merge(this.users, message.author.id, message.author);
5817
+ }
5818
+ #upsertMember(guildId, data) {
5819
+ const member = new GuildMember({ ...data, guild_id: guildId });
5820
+ if (this.#cache.users)
5821
+ this.#merge(this.users, member.user.id, member.user);
5822
+ if (!this.#cache.members)
5823
+ return member;
5824
+ return this.#merge(this.guilds.members(guildId), member.user.id, member);
5825
+ }
5826
+ #storeVoiceState(guildId, state) {
5827
+ const states = this.guilds.voiceStates(guildId);
5828
+ if (state.channel_id)
5829
+ states.set(state.user_id, state);
5830
+ else
5831
+ states.delete(state.user_id);
5832
+ }
5833
+ #upsertRole(guildId, data) {
5834
+ if (!this.#cache.roles)
5835
+ return new Role(data);
5836
+ return this.#merge(this.guilds.roles(guildId), data.id, new Role(data));
5837
+ }
5838
+ #merge(manager, id, next) {
5839
+ const existing = manager.get(id);
5840
+ if (!existing) {
5841
+ manager.set(id, next);
5842
+ return next;
5843
+ }
5844
+ for (const [key, value] of Object.entries(next))
5845
+ if (value !== undefined)
5846
+ existing[key] = value;
5847
+ return existing;
5848
+ }
5849
+ createCollector(event, options = {}) {
5850
+ const collector = new Collector(options);
5851
+ let order = 0;
5852
+ const listener = (...args) => {
5853
+ const item = args[0];
5854
+ const id = item?.id;
5855
+ const key = options.key?.(item) ?? (typeof id === "string" ? id : String(order++));
5856
+ collector.handle(key, item).catch((error) => this.emit("error" /* Error */, error instanceof Error ? error : new Error(String(error))));
5857
+ };
5858
+ this.on(event, listener);
5859
+ collector.onDispose(() => this.off(event, listener));
5860
+ return collector;
5861
+ }
5862
+ permissionsFor(memberId, guildOrChannelId) {
5863
+ let channel = this.channels.get(guildOrChannelId);
5864
+ if (channel?.isThread()) {
5865
+ channel = channel.parentId ? this.channels.get(channel.parentId) : undefined;
5866
+ if (!channel)
5867
+ return null;
5868
+ }
5869
+ const guildId = channel?.guildId ?? guildOrChannelId;
5870
+ const guild = this.guilds.get(guildId);
5871
+ const member = this.guilds.members(guildId).get(memberId);
5872
+ if (!guild || !member)
5873
+ return null;
5874
+ return computePermissions({
5875
+ guildId,
5876
+ ownerId: guild.ownerId,
5877
+ memberId,
5878
+ memberRoleIds: member.roleIds,
5879
+ roles: this.guilds.roles(guildId).values(),
5880
+ overwrites: channel?.permissionOverwrites
5881
+ });
5882
+ }
5883
+ fetchDefaultSoundboardSounds() {
5884
+ return this.rest.get(Routes.soundboardDefaultSounds());
5885
+ }
4493
5886
  async login(token) {
4494
5887
  if (this.state === "destroyed")
4495
5888
  throw new Error("Cannot login a destroyed client.");
@@ -4526,6 +5919,14 @@ class Client extends EventEmitter2 {
4526
5919
  return Promise.reject(new Error("Client is unauthenticated."));
4527
5920
  return this.rest.post(`/webhooks/${this.user.id}/${token}`, data);
4528
5921
  }
5922
+ interactionWebhookMessage(method, applicationId, token, messageId, data) {
5923
+ const path = messageId === "@original" ? Routes.interactionOriginalResponse(applicationId, token) : Routes.webhookMessage(applicationId, token, messageId);
5924
+ if (method === "GET")
5925
+ return this.rest.get(path);
5926
+ if (method === "PATCH")
5927
+ return this.rest.patch(path, data);
5928
+ return this.rest.delete(path);
5929
+ }
4529
5930
  fetchWebhook(id, token) {
4530
5931
  return this.rest.get(token ? `/webhooks/${id}/${token}` : `/webhooks/${id}`);
4531
5932
  }
@@ -4583,7 +5984,8 @@ export {
4583
5984
  PermissionSet,
4584
5985
  Permissions,
4585
5986
  PermissionsBitField,
5987
+ computePermissions,
4586
5988
  resolveGatewayIntents
4587
5989
  };
4588
5990
 
4589
- //# debugId=B9E28396E97D857564756E2164756E21
5991
+ //# debugId=29BD1D4A42C8D39264756E2164756E21