lunibee 0.2.3 → 0.2.4

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 (61) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +225 -225
  3. package/dist/builders/attachment.d.ts +8 -0
  4. package/dist/builders/commands.d.ts +122 -65
  5. package/dist/builders/components.d.ts +10 -31
  6. package/dist/builders/embed.d.ts +66 -33
  7. package/dist/builders/index.js +97 -131
  8. package/dist/builders/index.js.map +8 -8
  9. package/dist/collection/cache.d.ts +13 -6
  10. package/dist/collection/index.d.ts +90 -17
  11. package/dist/collection/index.js +442 -266
  12. package/dist/collection/index.js.map +4 -4
  13. package/dist/core/index.d.ts +8 -0
  14. package/dist/core/index.js +607 -352
  15. package/dist/core/index.js.map +47 -47
  16. package/dist/core/permissions.d.ts +7 -3
  17. package/dist/formatters/index.js +9 -5
  18. package/dist/formatters/index.js.map +3 -3
  19. package/dist/handlers/index.js +5 -10
  20. package/dist/handlers/index.js.map +3 -3
  21. package/dist/index.js +769 -587
  22. package/dist/index.js.map +65 -65
  23. package/dist/managers/base.d.ts +22 -14
  24. package/dist/managers/index.d.ts +2 -1
  25. package/dist/managers/index.js +445 -276
  26. package/dist/managers/index.js.map +26 -26
  27. package/dist/managers/message.d.ts +7 -3
  28. package/dist/rest/errors.d.ts +14 -7
  29. package/dist/rest/index.d.ts +24 -12
  30. package/dist/rest/index.js +54 -17
  31. package/dist/rest/index.js.map +14 -14
  32. package/dist/rest/redis.d.ts +1 -1
  33. package/dist/rest/route.d.ts +8 -4
  34. package/dist/rest/routes.d.ts +102 -48
  35. package/dist/rest/transport.d.ts +10 -5
  36. package/dist/rest/webhook.d.ts +9 -5
  37. package/dist/sharding/bus.d.ts +34 -17
  38. package/dist/sharding/index.d.ts +34 -17
  39. package/dist/sharding/index.js +64 -32
  40. package/dist/sharding/index.js.map +17 -17
  41. package/dist/structures/base.d.ts +19 -10
  42. package/dist/structures/channels.d.ts +28 -14
  43. package/dist/structures/index.js +9 -59
  44. package/dist/structures/index.js.map +19 -18
  45. package/dist/structures/interactions.d.ts +96 -48
  46. package/dist/structures/resources.d.ts +88 -44
  47. package/dist/types/gateway.d.ts +1 -1
  48. package/dist/types/index.js +20 -22
  49. package/dist/types/index.js.map +4 -4
  50. package/dist/utils/index.js.map +2 -2
  51. package/dist/voice/index.d.ts +12 -4
  52. package/dist/voice/index.js +14 -18
  53. package/dist/voice/index.js.map +3 -3
  54. package/dist/ws/decoder.d.ts +6 -2
  55. package/dist/ws/index.d.ts +25 -13
  56. package/dist/ws/index.js +63 -31
  57. package/dist/ws/index.js.map +14 -14
  58. package/dist/ws/protocol.d.ts +10 -2
  59. package/dist/ws/session.d.ts +14 -4
  60. package/dist/ws/state.d.ts +22 -11
  61. package/package.json +15 -14
package/dist/index.js CHANGED
@@ -114,60 +114,7 @@ var Permissions = {
114
114
  PinMessages: 1n << 51n,
115
115
  BypassSlowmode: 1n << 52n
116
116
  };
117
- var PermissionFlagsBits = {
118
- CreateInstantInvite: 1n << 0n,
119
- KickMembers: 1n << 1n,
120
- BanMembers: 1n << 2n,
121
- Administrator: 1n << 3n,
122
- ManageChannels: 1n << 4n,
123
- ManageGuild: 1n << 5n,
124
- AddReactions: 1n << 6n,
125
- ViewAuditLog: 1n << 7n,
126
- PrioritySpeaker: 1n << 8n,
127
- Stream: 1n << 9n,
128
- ViewChannel: 1n << 10n,
129
- SendMessages: 1n << 11n,
130
- SendTTSMessages: 1n << 12n,
131
- ManageMessages: 1n << 13n,
132
- EmbedLinks: 1n << 14n,
133
- AttachFiles: 1n << 15n,
134
- ReadMessageHistory: 1n << 16n,
135
- MentionEveryone: 1n << 17n,
136
- UseExternalEmojis: 1n << 18n,
137
- ViewGuildInsights: 1n << 19n,
138
- Connect: 1n << 20n,
139
- Speak: 1n << 21n,
140
- MuteMembers: 1n << 22n,
141
- DeafenMembers: 1n << 23n,
142
- MoveMembers: 1n << 24n,
143
- UseVAD: 1n << 25n,
144
- ChangeNickname: 1n << 26n,
145
- ManageNicknames: 1n << 27n,
146
- ManageRoles: 1n << 28n,
147
- ManageWebhooks: 1n << 29n,
148
- ManageGuildExpressions: 1n << 30n,
149
- UseApplicationCommands: 1n << 31n,
150
- RequestToSpeak: 1n << 32n,
151
- ManageEvents: 1n << 33n,
152
- ManageThreads: 1n << 34n,
153
- CreatePublicThreads: 1n << 35n,
154
- CreatePrivateThreads: 1n << 36n,
155
- UseExternalStickers: 1n << 37n,
156
- SendMessagesInThreads: 1n << 38n,
157
- UseEmbeddedActivities: 1n << 39n,
158
- ModerateMembers: 1n << 40n,
159
- ViewCreatorMonetizationAnalytics: 1n << 41n,
160
- UseSoundboard: 1n << 42n,
161
- CreateGuildExpressions: 1n << 43n,
162
- CreateEvents: 1n << 44n,
163
- UseExternalSounds: 1n << 45n,
164
- SendVoiceMessages: 1n << 46n,
165
- SetVoiceChannelStatus: 1n << 48n,
166
- SendPolls: 1n << 49n,
167
- UseExternalApps: 1n << 50n,
168
- PinMessages: 1n << 51n,
169
- BypassSlowmode: 1n << 52n
170
- };
117
+ var PermissionFlagsBits = Permissions;
171
118
 
172
119
  class PermissionSet {
173
120
  bitfield;
@@ -468,6 +415,9 @@ function computePermissions(context) {
468
415
  const member = overwrites.find((o) => o.type === 1 /* Member */ && o.id === context.memberId);
469
416
  if (member)
470
417
  base = base & ~bits(member.deny) | bits(member.allow);
418
+ const until = context.timedOutUntil instanceof Date ? context.timedOutUntil.getTime() : context.timedOutUntil ?? 0;
419
+ if (until > Date.now())
420
+ base &= Permission.viewChannel | Permission.readMessageHistory;
471
421
  return new PermissionSet(base);
472
422
  }
473
423
  // packages/core/src/events.ts
@@ -742,28 +692,26 @@ var IntentBits = {
742
692
  };
743
693
  var Intents = IntentBits;
744
694
  function resolveGatewayIntents(intents) {
745
- if (typeof intents === "number")
746
- return intents;
747
- if (intents && typeof intents === "object" && !Array.isArray(intents))
695
+ if (Array.isArray(intents))
696
+ return intents.reduce((acc, intent) => acc | resolveIntent(intent), 0);
697
+ if (typeof intents === "object")
748
698
  return intents.bitfield;
749
- if (Array.isArray(intents)) {
750
- return intents.reduce((acc, intent) => {
751
- return acc | resolveGatewayIntents(intent);
752
- }, 0);
753
- }
754
- if (typeof intents === "string") {
755
- if (intents in GatewayIntentBits)
756
- return GatewayIntentBits[intents];
757
- if (intents in IntentBits)
758
- return IntentBits[intents];
759
- const lower = intents.charAt(0).toLowerCase() + intents.slice(1);
760
- if (lower in IntentBits)
761
- return IntentBits[lower];
762
- const num = Number(intents);
763
- if (!Number.isNaN(num))
764
- return num;
765
- }
766
- return 0;
699
+ return resolveIntent(intents);
700
+ }
701
+ function resolveIntent(intent) {
702
+ if (typeof intent === "number")
703
+ return intent;
704
+ const bits = {
705
+ ...IntentBits,
706
+ ...GatewayIntentBits
707
+ };
708
+ const lower = intent.charAt(0).toLowerCase() + intent.slice(1);
709
+ if (Object.hasOwn(bits, intent))
710
+ return bits[intent];
711
+ if (Object.hasOwn(bits, lower))
712
+ return bits[lower];
713
+ const num = Number(intent);
714
+ return Number.isNaN(num) ? 0 : num;
767
715
  }
768
716
 
769
717
  class IntentsBitField {
@@ -830,6 +778,24 @@ var ChannelEnum = {
830
778
  GuildForum: 15,
831
779
  GuildMedia: 16
832
780
  };
781
+ var ComponentEnum = {
782
+ ActionRow: 1,
783
+ Button: 2,
784
+ StringSelect: 3,
785
+ TextInput: 4,
786
+ UserSelect: 5,
787
+ RoleSelect: 6,
788
+ MentionableSelect: 7,
789
+ ChannelSelect: 8,
790
+ Section: 9,
791
+ TextDisplay: 10,
792
+ Thumbnail: 11,
793
+ MediaGallery: 12,
794
+ File: 13,
795
+ Separator: 14,
796
+ ContentInventoryEntry: 16,
797
+ Container: 17
798
+ };
833
799
  var ButtonType = {
834
800
  Primary: 1,
835
801
  Secondary: 2,
@@ -904,64 +870,36 @@ var StickerType = StickerEnum;
904
870
  var StickerFormatType = StickerFormatEnum;
905
871
  // packages/collection/src/cache.ts
906
872
  class Cache {
907
- #entries = new Collection;
908
- #maxSize;
909
- #ttl;
910
- #timer;
873
+ #entries;
911
874
  constructor(options = {}) {
912
- this.#maxSize = options.maxSize ?? Infinity;
913
- this.#ttl = options.ttl ?? 0;
914
- if (!Number.isInteger(this.#maxSize) && this.#maxSize !== Infinity || this.#maxSize < 1)
875
+ const maxSize = options.maxSize ?? Infinity;
876
+ const ttl = options.ttl ?? 0;
877
+ if (!Number.isInteger(maxSize) && maxSize !== Infinity || maxSize < 1)
915
878
  throw new RangeError("Cache maxSize must be a positive integer.");
916
- if (!Number.isFinite(this.#ttl) || this.#ttl < 0)
879
+ if (!Number.isFinite(ttl) || ttl < 0)
917
880
  throw new RangeError("Cache ttl must be a non-negative finite number.");
918
- if (this.#ttl > 0) {
919
- const interval = options.sweepInterval ?? Math.min(this.#ttl, 60000);
881
+ if (ttl > 0) {
882
+ const interval = options.sweepInterval ?? Math.min(ttl, 60000);
920
883
  if (!Number.isFinite(interval) || interval < 1)
921
884
  throw new RangeError("Cache sweepInterval must be positive.");
922
- this.#timer = setInterval(() => this.sweep(), interval);
923
- this.#timer.unref?.();
924
885
  }
886
+ this.#entries = new Collection(null, {
887
+ ttl: ttl > 0 ? ttl : undefined,
888
+ maxSize: maxSize === Infinity ? undefined : maxSize,
889
+ slide: false
890
+ });
925
891
  }
926
892
  get size() {
927
- this.#sweepExpired();
928
893
  return this.#entries.size;
929
894
  }
930
895
  get(key) {
931
- const entry = this.#entries.get(key);
932
- if (!entry)
933
- return;
934
- if (entry.expiresAt > 0 && entry.expiresAt <= Date.now()) {
935
- this.#entries.delete(key);
936
- return;
937
- }
938
- this.#entries.delete(key);
939
- this.#entries.set(key, entry);
940
- return entry.value;
896
+ return this.#entries.get(key);
941
897
  }
942
898
  has(key) {
943
- const entry = this.#entries.get(key);
944
- if (!entry)
945
- return false;
946
- if (entry.expiresAt > 0 && entry.expiresAt <= Date.now()) {
947
- this.#entries.delete(key);
948
- return false;
949
- }
950
- return true;
899
+ return this.#entries.has(key);
951
900
  }
952
901
  set(key, value) {
953
- const expiresAt = this.#ttl > 0 ? Date.now() + this.#ttl : 0;
954
- this.#entries.delete(key);
955
- this.#entries.set(key, { value, expiresAt });
956
- if (this.#maxSize !== Infinity) {
957
- while (this.#entries.size > this.#maxSize) {
958
- const oldest = this.#entries.firstKey();
959
- if (oldest !== undefined)
960
- this.#entries.delete(oldest);
961
- else
962
- break;
963
- }
964
- }
902
+ this.#entries.set(key, value);
965
903
  return this;
966
904
  }
967
905
  delete(key) {
@@ -971,95 +909,52 @@ class Cache {
971
909
  this.#entries.clear();
972
910
  }
973
911
  invalidate(predicate) {
974
- return this.#entries.sweep((entry, key) => predicate(entry.value, key));
912
+ return this.#entries.sweep(predicate);
975
913
  }
976
914
  sweep() {
977
- return this.#entries.sweep((entry) => this.#expired(entry));
978
- }
979
- dispose() {
980
- if (this.#timer)
981
- clearInterval(this.#timer);
982
- this.#timer = undefined;
915
+ return this.#entries.purge();
983
916
  }
917
+ dispose() {}
984
918
  values() {
985
- this.#sweepExpired();
986
- return this.#entries.map((entry) => entry.value);
919
+ return [...this.#entries.values()];
987
920
  }
988
921
  entries() {
989
- this.#sweepExpired();
990
- return this.#entries.map((entry, key) => [key, entry.value]);
991
- }
992
- #expired(entry) {
993
- return entry.expiresAt > 0 && entry.expiresAt <= Date.now();
994
- }
995
- #sweepExpired() {
996
- if (this.#ttl > 0)
997
- this.sweep();
922
+ return [...this.#entries.entries()];
998
923
  }
999
924
  }
1000
925
 
1001
926
  // packages/collection/src/index.ts
1002
- class RecencyList {
1003
- #nodes = new Map;
1004
- #oldest;
1005
- #newest;
1006
- get size() {
1007
- return this.#nodes.size;
1008
- }
1009
- oldest() {
1010
- return this.#oldest?.key;
1011
- }
1012
- touch(key) {
1013
- const node = this.#nodes.get(key);
1014
- if (node)
1015
- return this.#moveNewest(node);
1016
- const created = { key, older: this.#newest };
1017
- if (this.#newest)
1018
- this.#newest.newer = created;
1019
- else
1020
- this.#oldest = created;
1021
- this.#newest = created;
1022
- this.#nodes.set(key, created);
1023
- }
1024
- promote(key) {
1025
- const node = this.#nodes.get(key);
1026
- if (node)
1027
- this.#moveNewest(node);
1028
- }
1029
- delete(key) {
1030
- const node = this.#nodes.get(key);
1031
- if (!node)
1032
- return false;
1033
- this.#unlink(node);
1034
- this.#nodes.delete(key);
1035
- return true;
1036
- }
1037
- clear() {
1038
- this.#nodes.clear();
1039
- this.#oldest = this.#newest = undefined;
1040
- }
1041
- #unlink(node) {
1042
- if (node.older)
1043
- node.older.newer = node.newer;
1044
- else
1045
- this.#oldest = node.newer;
1046
- if (node.newer)
1047
- node.newer.older = node.older;
1048
- else
1049
- this.#newest = node.older;
1050
- node.older = node.newer = undefined;
1051
- }
1052
- #moveNewest(node) {
1053
- if (node === this.#newest)
1054
- return;
1055
- this.#unlink(node);
1056
- node.older = this.#newest;
1057
- if (this.#newest)
1058
- this.#newest.newer = node;
1059
- else
1060
- this.#oldest = node;
1061
- this.#newest = node;
927
+ function newPolicy(options = {}) {
928
+ return {
929
+ ttl: options.ttl,
930
+ maxSize: options.maxSize,
931
+ slide: options.slide ?? true,
932
+ onEvict: options.onEvict,
933
+ expired: 0,
934
+ evicted: 0,
935
+ entries: new Map,
936
+ oldest: undefined,
937
+ newest: undefined,
938
+ lruSize: 0,
939
+ heap: [],
940
+ armedFor: Infinity
941
+ };
942
+ }
943
+ function peekOf(collection, key) {
944
+ return collection instanceof Map ? Map.prototype.get.call(collection, key) : collection.get(key);
945
+ }
946
+ var mapGet = Map.prototype.get;
947
+ var mapHas = Map.prototype.has;
948
+ function sample(items, amount) {
949
+ if (!Number.isInteger(amount) || amount < 0)
950
+ throw new RangeError("amount must be a non-negative integer.");
951
+ const count = Math.min(amount, items.length);
952
+ for (let i = 0;i < count; i++) {
953
+ const j = i + Math.floor(Math.random() * (items.length - i));
954
+ [items[i], items[j]] = [items[j], items[i]];
1062
955
  }
956
+ items.length = count;
957
+ return items;
1063
958
  }
1064
959
  function assertTTL(ttl) {
1065
960
  if (ttl !== undefined && (!Number.isFinite(ttl) || ttl <= 0))
@@ -1067,81 +962,90 @@ function assertTTL(ttl) {
1067
962
  }
1068
963
 
1069
964
  class Collection extends Map {
1070
- #ttl;
1071
- #maxSize;
1072
- #onEvict;
1073
- #expiry = new Map;
1074
- #lru = new RecencyList;
1075
- #stats = {
1076
- hits: 0,
1077
- misses: 0,
1078
- expired: 0,
1079
- evicted: 0
1080
- };
1081
- #heap = [];
1082
- #timer;
1083
- #armedFor = Infinity;
965
+ #policy;
966
+ #hits = 0;
967
+ #misses = 0;
1084
968
  constructor(entries, options = {}) {
1085
969
  super();
1086
970
  assertTTL(options.ttl);
1087
971
  if (options.maxSize !== undefined && (!Number.isInteger(options.maxSize) || options.maxSize <= 0))
1088
972
  throw new RangeError("maxSize must be a positive integer.");
1089
- this.#ttl = options.ttl;
1090
- this.#maxSize = options.maxSize;
1091
- this.#onEvict = options.onEvict;
973
+ if (options.ttl !== undefined || options.maxSize !== undefined || options.slide !== undefined || options.onEvict !== undefined)
974
+ this.#policy = newPolicy(options);
1092
975
  if (entries)
1093
976
  for (const [key, value] of entries)
1094
977
  this.set(key, value);
1095
978
  }
1096
979
  set(key, value, ttl) {
980
+ if (ttl === undefined && this.#policy === undefined)
981
+ return super.set(key, value);
1097
982
  assertTTL(ttl);
1098
- const window = ttl ?? this.#ttl;
1099
- if (this.#maxSize !== undefined) {
1100
- this.#lru.touch(key);
1101
- }
1102
- super.set(key, value);
983
+ const window = ttl ?? this.#policy?.ttl;
1103
984
  if (window !== undefined)
1104
- this.#schedule(key, window);
1105
- else if (this.#expiry.size > 0)
1106
- this.#expiry.delete(key);
985
+ this.#policy ??= newPolicy();
986
+ if (!this.#policy)
987
+ return super.set(key, value);
988
+ const before = super.size;
989
+ super.set(key, value);
990
+ this.#track(key, value, window, super.size !== before);
1107
991
  this.#enforceCap();
1108
992
  return this;
1109
993
  }
1110
994
  setWithoutTTL(key, value) {
1111
- if (this.#expiry.size > 0)
1112
- this.#expiry.delete(key);
1113
- if (this.#lru.size > 0)
1114
- this.#lru.delete(key);
995
+ if (this.#policy)
996
+ this.#forget(key);
1115
997
  super.set(key, value);
1116
998
  return this;
1117
999
  }
1118
1000
  get(key) {
1119
- if (this.#expireIfDue(key)) {
1120
- this.#stats.misses++;
1001
+ const policy = this.#policy;
1002
+ const entry = policy?.entries.get(key);
1003
+ if (entry === undefined) {
1004
+ const value = mapGet.call(this, key);
1005
+ if (value !== undefined || mapHas.call(this, key)) {
1006
+ this.#hits++;
1007
+ return value;
1008
+ }
1009
+ this.#misses++;
1121
1010
  return;
1122
1011
  }
1123
- const value = super.get(key);
1124
- if (value === undefined && !super.has(key)) {
1125
- this.#stats.misses++;
1012
+ const timed = entry.window !== 0;
1013
+ const now = timed ? Date.now() : 0;
1014
+ if (timed && entry.deadline <= now) {
1015
+ this.#expire(entry);
1016
+ this.#misses++;
1126
1017
  return;
1127
1018
  }
1128
- this.#stats.hits++;
1129
- const expiry = this.#expiry.get(key);
1130
- if (expiry)
1131
- expiry.deadline = Date.now() + expiry.window;
1132
- this.#lru.promote(key);
1133
- return value;
1019
+ this.#hits++;
1020
+ if (timed && policy.slide)
1021
+ entry.deadline = now + entry.window;
1022
+ if (entry.inLru)
1023
+ this.#promote(policy, entry);
1024
+ return entry.value;
1025
+ }
1026
+ ensure(key, factory, ttl) {
1027
+ const existing = this.get(key);
1028
+ if (existing !== undefined || super.has(key))
1029
+ return existing;
1030
+ const created = factory(key, this);
1031
+ this.set(key, created, ttl);
1032
+ return created;
1134
1033
  }
1135
1034
  peek(key) {
1136
1035
  if (!this.#expireIfDue(key) && super.has(key)) {
1137
- this.#stats.hits++;
1036
+ this.#hits++;
1138
1037
  return super.get(key);
1139
1038
  }
1140
- this.#stats.misses++;
1039
+ this.#misses++;
1141
1040
  return;
1142
1041
  }
1143
1042
  get stats() {
1144
- return { ...this.#stats };
1043
+ return {
1044
+ hits: this.#hits,
1045
+ misses: this.#misses,
1046
+ expired: this.#policy?.expired ?? 0,
1047
+ evicted: this.#policy?.evicted ?? 0
1048
+ };
1145
1049
  }
1146
1050
  has(key) {
1147
1051
  return !this.#expireIfDue(key) && super.has(key);
@@ -1149,19 +1053,23 @@ class Collection extends Map {
1149
1053
  delete(key) {
1150
1054
  if (this.#expireIfDue(key))
1151
1055
  return false;
1152
- this.#expiry.delete(key);
1153
- this.#lru.delete(key);
1056
+ if (this.#policy)
1057
+ this.#forget(key);
1154
1058
  return super.delete(key);
1155
1059
  }
1156
1060
  clear() {
1157
1061
  super.clear();
1158
- this.#expiry.clear();
1159
- this.#lru.clear();
1160
- this.#heap.length = 0;
1161
- if (this.#timer)
1162
- clearTimeout(this.#timer);
1163
- this.#timer = undefined;
1164
- this.#armedFor = Infinity;
1062
+ const policy = this.#policy;
1063
+ if (!policy)
1064
+ return;
1065
+ policy.entries.clear();
1066
+ policy.oldest = policy.newest = undefined;
1067
+ policy.lruSize = 0;
1068
+ policy.heap.length = 0;
1069
+ if (policy.timer)
1070
+ clearTimeout(policy.timer);
1071
+ policy.timer = undefined;
1072
+ policy.armedFor = Infinity;
1165
1073
  }
1166
1074
  get size() {
1167
1075
  this.purge();
@@ -1189,11 +1097,11 @@ class Collection extends Map {
1189
1097
  ttlRemaining(key) {
1190
1098
  if (this.#expireIfDue(key))
1191
1099
  return;
1192
- const expiry = this.#expiry.get(key);
1193
- return expiry && Math.max(0, expiry.deadline - Date.now());
1100
+ const entry = this.#policy?.entries.get(key);
1101
+ return entry && entry.window !== 0 ? Math.max(0, entry.deadline - Date.now()) : undefined;
1194
1102
  }
1195
1103
  purge() {
1196
- if (this.#expiry.size === 0)
1104
+ if (!this.#policy || this.#policy.heap.length === 0)
1197
1105
  return 0;
1198
1106
  const now = Date.now();
1199
1107
  let removed = 0;
@@ -1204,133 +1112,255 @@ class Collection extends Map {
1204
1112
  this.#remove(due.key);
1205
1113
  removed++;
1206
1114
  }
1207
- this.#stats.expired += removed;
1115
+ this.#policy.expired += removed;
1208
1116
  this.#rearm();
1209
1117
  for (const [key, value] of dropped)
1210
1118
  this.#notify(key, value, "expired");
1211
1119
  return removed;
1212
1120
  }
1213
1121
  #expireIfDue(key) {
1214
- const expiry = this.#expiry.get(key);
1215
- if (!expiry || expiry.deadline > Date.now())
1122
+ const entry = this.#policy?.entries.get(key);
1123
+ if (!entry || entry.window === 0 || entry.deadline > Date.now())
1216
1124
  return false;
1217
- const value = super.get(key);
1218
- this.#remove(key);
1219
- this.#stats.expired++;
1220
- this.#notify(key, value, "expired");
1125
+ this.#expire(entry);
1221
1126
  return true;
1222
1127
  }
1128
+ #expire(entry) {
1129
+ const value = super.get(entry.key);
1130
+ this.#remove(entry.key);
1131
+ this.#policy.expired++;
1132
+ this.#notify(entry.key, value, "expired");
1133
+ }
1223
1134
  #remove(key) {
1224
- this.#expiry.delete(key);
1225
- this.#lru.delete(key);
1135
+ this.#forget(key);
1226
1136
  super.delete(key);
1227
1137
  }
1138
+ #forget(key) {
1139
+ const policy = this.#policy;
1140
+ const entry = policy.entries.get(key);
1141
+ if (!entry)
1142
+ return;
1143
+ if (entry.inLru)
1144
+ this.#unlink(policy, entry);
1145
+ policy.entries.delete(key);
1146
+ }
1147
+ #track(key, value, window, isNew) {
1148
+ const policy = this.#policy;
1149
+ const lru = policy.maxSize !== undefined;
1150
+ let entry = isNew ? undefined : policy.entries.get(key);
1151
+ if (entry)
1152
+ entry.value = value;
1153
+ if (window === undefined) {
1154
+ if (entry && entry.window !== 0) {
1155
+ if (lru)
1156
+ entry = this.#replace(policy, entry, 0, 0);
1157
+ else {
1158
+ this.#forget(key);
1159
+ return;
1160
+ }
1161
+ }
1162
+ if (!entry && lru) {
1163
+ entry = this.#create(key, value, 0, 0);
1164
+ policy.entries.set(key, entry);
1165
+ }
1166
+ if (entry)
1167
+ this.#promote(policy, entry);
1168
+ return;
1169
+ }
1170
+ const deadline = Date.now() + window;
1171
+ if (entry && entry.window !== 0) {
1172
+ entry.deadline = deadline;
1173
+ entry.window = window;
1174
+ if (deadline < entry.filed)
1175
+ entry = this.#replace(policy, entry, window, deadline);
1176
+ else {
1177
+ if (entry.inLru)
1178
+ this.#promote(policy, entry);
1179
+ return;
1180
+ }
1181
+ } else if (entry) {
1182
+ entry.window = window;
1183
+ entry.deadline = entry.filed = deadline;
1184
+ } else {
1185
+ entry = this.#create(key, value, window, deadline);
1186
+ policy.entries.set(key, entry);
1187
+ }
1188
+ if (lru)
1189
+ this.#promote(policy, entry);
1190
+ this.#heapPush(entry);
1191
+ if (policy.heap.length > 2 * policy.entries.size + 8)
1192
+ this.#compact();
1193
+ if (policy.timer === undefined || deadline < policy.armedFor)
1194
+ this.#rearm();
1195
+ }
1196
+ #create(key, value, window, deadline) {
1197
+ return {
1198
+ key,
1199
+ value,
1200
+ older: undefined,
1201
+ newer: undefined,
1202
+ inLru: false,
1203
+ window,
1204
+ deadline,
1205
+ filed: deadline
1206
+ };
1207
+ }
1208
+ #replace(policy, old, window, deadline) {
1209
+ const entry = {
1210
+ ...old,
1211
+ window,
1212
+ deadline,
1213
+ filed: deadline
1214
+ };
1215
+ if (old.inLru) {
1216
+ if (old.older)
1217
+ old.older.newer = entry;
1218
+ else
1219
+ policy.oldest = entry;
1220
+ if (old.newer)
1221
+ old.newer.older = entry;
1222
+ else
1223
+ policy.newest = entry;
1224
+ }
1225
+ policy.entries.set(old.key, entry);
1226
+ return entry;
1227
+ }
1228
+ #promote(policy, entry) {
1229
+ if (entry === policy.newest)
1230
+ return;
1231
+ if (entry.inLru)
1232
+ this.#unlink(policy, entry, true);
1233
+ else {
1234
+ entry.inLru = true;
1235
+ policy.lruSize++;
1236
+ }
1237
+ entry.older = policy.newest;
1238
+ entry.newer = undefined;
1239
+ if (policy.newest)
1240
+ policy.newest.newer = entry;
1241
+ else
1242
+ policy.oldest = entry;
1243
+ policy.newest = entry;
1244
+ }
1245
+ #unlink(policy, entry, keepCount = false) {
1246
+ if (entry.older)
1247
+ entry.older.newer = entry.newer;
1248
+ else
1249
+ policy.oldest = entry.newer;
1250
+ if (entry.newer)
1251
+ entry.newer.older = entry.older;
1252
+ else
1253
+ policy.newest = entry.older;
1254
+ entry.older = entry.newer = undefined;
1255
+ if (!keepCount) {
1256
+ entry.inLru = false;
1257
+ policy.lruSize--;
1258
+ }
1259
+ }
1260
+ #derived() {
1261
+ const Species = this.constructor[Symbol.species] ?? Collection;
1262
+ return new Species;
1263
+ }
1228
1264
  #notify(key, value, reason) {
1229
- if (!this.#onEvict)
1265
+ const onEvict = this.#policy?.onEvict;
1266
+ if (!onEvict)
1230
1267
  return;
1231
1268
  try {
1232
- this.#onEvict(key, value, reason);
1269
+ onEvict(key, value, reason);
1233
1270
  } catch {}
1234
1271
  }
1235
1272
  #enforceCap() {
1236
- if (this.#maxSize === undefined)
1273
+ const policy = this.#policy;
1274
+ const max = policy.maxSize;
1275
+ if (max === undefined)
1237
1276
  return;
1238
- while (this.#lru.size > this.#maxSize) {
1239
- const oldest = this.#lru.oldest();
1240
- const value = super.get(oldest);
1241
- this.#remove(oldest);
1242
- this.#stats.evicted++;
1243
- this.#notify(oldest, value, "evicted");
1277
+ if (policy.lruSize > max && policy.heap.length > 0 && policy.heap[0].filed <= Date.now())
1278
+ this.purge();
1279
+ while (policy.lruSize > max) {
1280
+ const oldest = policy.oldest;
1281
+ const value = policy.onEvict ? super.get(oldest.key) : undefined;
1282
+ this.#unlink(policy, oldest);
1283
+ policy.entries.delete(oldest.key);
1284
+ super.delete(oldest.key);
1285
+ policy.evicted++;
1286
+ this.#notify(oldest.key, value, "evicted");
1244
1287
  }
1245
1288
  }
1246
- #schedule(key, window) {
1247
- const deadline = Date.now() + window;
1248
- const expiry = this.#expiry.get(key);
1249
- if (expiry) {
1250
- expiry.deadline = deadline;
1251
- expiry.window = window;
1252
- if (deadline >= expiry.filed)
1253
- return;
1254
- expiry.filed = deadline;
1255
- } else
1256
- this.#expiry.set(key, { deadline, window, filed: deadline });
1257
- this.#heapPush({ key, deadline });
1258
- if (this.#heap.length > 2 * this.#expiry.size + 8)
1259
- this.#compact();
1260
- this.#rearm();
1261
- }
1262
1289
  #nextDeadline() {
1290
+ const policy = this.#policy;
1263
1291
  for (;; ) {
1264
- const top = this.#heap[0];
1292
+ const top = policy.heap[0];
1265
1293
  if (top === undefined)
1266
1294
  return Infinity;
1267
- const expiry = this.#expiry.get(top.key);
1268
- if (!expiry || expiry.filed !== top.deadline) {
1295
+ if (policy.entries.get(top.key) !== top) {
1269
1296
  this.#heapPop();
1270
1297
  continue;
1271
1298
  }
1272
- if (expiry.deadline === top.deadline)
1273
- return top.deadline;
1299
+ if (top.deadline === top.filed)
1300
+ return top.filed;
1274
1301
  this.#heapPop();
1275
- expiry.filed = expiry.deadline;
1276
- this.#heapPush({ key: top.key, deadline: expiry.deadline });
1302
+ top.filed = top.deadline;
1303
+ this.#heapPush(top);
1277
1304
  }
1278
1305
  }
1279
1306
  #compact() {
1280
- const live = this.#heap.filter((record) => this.#expiry.get(record.key)?.filed === record.deadline);
1281
- this.#heap.length = 0;
1282
- for (const record of live)
1283
- this.#heapPush(record);
1307
+ const policy = this.#policy;
1308
+ const live = policy.heap.filter((entry) => policy.entries.get(entry.key) === entry);
1309
+ policy.heap.length = 0;
1310
+ for (const entry of live)
1311
+ this.#heapPush(entry);
1284
1312
  }
1285
1313
  #rearm() {
1314
+ const p = this.#policy;
1286
1315
  const deadline = this.#nextDeadline();
1287
- if (this.#timer !== undefined && deadline >= this.#armedFor)
1316
+ if (p.timer !== undefined && deadline >= p.armedFor)
1288
1317
  return;
1289
- if (this.#timer)
1290
- clearTimeout(this.#timer);
1291
- this.#timer = undefined;
1292
- this.#armedFor = deadline;
1318
+ if (p.timer)
1319
+ clearTimeout(p.timer);
1320
+ p.timer = undefined;
1321
+ p.armedFor = deadline;
1293
1322
  if (deadline === Infinity)
1294
1323
  return;
1295
- this.#timer = setTimeout(() => {
1296
- this.#timer = undefined;
1297
- this.#armedFor = Infinity;
1324
+ p.timer = setTimeout(() => {
1325
+ p.timer = undefined;
1326
+ p.armedFor = Infinity;
1298
1327
  this.purge();
1299
1328
  }, Math.max(0, deadline - Date.now()));
1300
- this.#timer.unref?.();
1329
+ p.timer.unref?.();
1301
1330
  }
1302
- #heapPush(record) {
1303
- const heap = this.#heap;
1304
- heap.push(record);
1305
- let i = heap.length - 1;
1331
+ #heapPush(entry) {
1332
+ const heap = this.#policy.heap;
1333
+ let i = heap.length;
1334
+ heap.push(entry);
1306
1335
  while (i > 0) {
1307
1336
  const parent = i - 1 >> 1;
1308
- if (heap[parent].deadline <= heap[i].deadline)
1337
+ const above = heap[parent];
1338
+ if (above.filed <= entry.filed)
1309
1339
  break;
1310
- [heap[parent], heap[i]] = [heap[i], heap[parent]];
1340
+ heap[i] = above;
1311
1341
  i = parent;
1312
1342
  }
1343
+ heap[i] = entry;
1313
1344
  }
1314
1345
  #heapPop() {
1315
- const heap = this.#heap;
1346
+ const heap = this.#policy.heap;
1316
1347
  const top = heap[0];
1317
1348
  const last = heap.pop();
1318
1349
  if (top === undefined || heap.length === 0)
1319
1350
  return top;
1320
- heap[0] = last;
1321
- for (let i = 0;; ) {
1322
- const left = 2 * i + 1;
1323
- const right = left + 1;
1324
- let smallest = i;
1325
- if (left < heap.length && heap[left].deadline < heap[smallest].deadline)
1326
- smallest = left;
1327
- if (right < heap.length && heap[right].deadline < heap[smallest].deadline)
1328
- smallest = right;
1329
- if (smallest === i)
1351
+ let i = 0;
1352
+ for (;; ) {
1353
+ let child = 2 * i + 1;
1354
+ if (child >= heap.length)
1355
+ break;
1356
+ if (child + 1 < heap.length && heap[child + 1].filed < heap[child].filed)
1357
+ child++;
1358
+ if (heap[child].filed >= last.filed)
1330
1359
  break;
1331
- [heap[smallest], heap[i]] = [heap[i], heap[smallest]];
1332
- i = smallest;
1360
+ heap[i] = heap[child];
1361
+ i = child;
1333
1362
  }
1363
+ heap[i] = last;
1334
1364
  return top;
1335
1365
  }
1336
1366
  first() {
@@ -1362,8 +1392,26 @@ class Collection extends Map {
1362
1392
  }
1363
1393
  return;
1364
1394
  }
1395
+ findLast(predicate) {
1396
+ const entries = [...this];
1397
+ for (let i = entries.length - 1;i >= 0; i--) {
1398
+ const [key, value] = entries[i];
1399
+ if (predicate(value, key, this))
1400
+ return value;
1401
+ }
1402
+ return;
1403
+ }
1404
+ findLastKey(predicate) {
1405
+ const entries = [...this];
1406
+ for (let i = entries.length - 1;i >= 0; i--) {
1407
+ const [key, value] = entries[i];
1408
+ if (predicate(value, key, this))
1409
+ return key;
1410
+ }
1411
+ return;
1412
+ }
1365
1413
  filter(predicate) {
1366
- const result = new Collection;
1414
+ const result = this.#derived();
1367
1415
  for (const [key, value] of this) {
1368
1416
  if (predicate(value, key, this))
1369
1417
  result.set(key, value);
@@ -1407,7 +1455,7 @@ class Collection extends Map {
1407
1455
  return [...this.entries()];
1408
1456
  }
1409
1457
  clone() {
1410
- const copy = new Collection;
1458
+ const copy = this.#derived();
1411
1459
  for (const [key, value] of this)
1412
1460
  copy.set(key, value);
1413
1461
  return copy;
@@ -1462,7 +1510,7 @@ class Collection extends Map {
1462
1510
  return result;
1463
1511
  }
1464
1512
  intersection(other) {
1465
- const result = new Collection;
1513
+ const result = this.#derived();
1466
1514
  for (const [key, value] of this) {
1467
1515
  if (other.has(key))
1468
1516
  result.set(key, value);
@@ -1470,7 +1518,7 @@ class Collection extends Map {
1470
1518
  return result;
1471
1519
  }
1472
1520
  difference(other) {
1473
- const result = new Collection;
1521
+ const result = this.#derived();
1474
1522
  for (const [key, value] of this) {
1475
1523
  if (!other.has(key))
1476
1524
  result.set(key, value);
@@ -1478,8 +1526,8 @@ class Collection extends Map {
1478
1526
  return result;
1479
1527
  }
1480
1528
  partition(predicate) {
1481
- const pass = new Collection;
1482
- const fail = new Collection;
1529
+ const pass = this.#derived();
1530
+ const fail = this.#derived();
1483
1531
  for (const [key, value] of this) {
1484
1532
  if (predicate(value, key, this))
1485
1533
  pass.set(key, value);
@@ -1488,6 +1536,81 @@ class Collection extends Map {
1488
1536
  }
1489
1537
  return [pass, fail];
1490
1538
  }
1539
+ symmetricDifference(other) {
1540
+ const result = this.#derived();
1541
+ for (const [key, value] of this)
1542
+ if (!other.has(key))
1543
+ result.set(key, value);
1544
+ for (const [key, value] of other)
1545
+ if (!this.has(key))
1546
+ result.set(key, value);
1547
+ return result;
1548
+ }
1549
+ concat(...collections) {
1550
+ const result = this.clone();
1551
+ for (const collection of collections)
1552
+ for (const [key, value] of collection)
1553
+ result.set(key, value);
1554
+ return result;
1555
+ }
1556
+ merge(other, whenInSelf, whenInOther, whenInBoth) {
1557
+ const result = this.#derived();
1558
+ const decide = (key, kept) => {
1559
+ if (kept.keep)
1560
+ result.set(key, kept.value);
1561
+ };
1562
+ for (const [key, value] of this) {
1563
+ decide(key, other.has(key) ? whenInBoth(value, peekOf(other, key), key) : whenInSelf(value, key));
1564
+ }
1565
+ for (const [key, value] of other)
1566
+ if (!this.has(key))
1567
+ decide(key, whenInOther(value, key));
1568
+ return result;
1569
+ }
1570
+ equals(other) {
1571
+ if (!other)
1572
+ return false;
1573
+ if (other === this)
1574
+ return true;
1575
+ if (this.size !== other.size)
1576
+ return false;
1577
+ for (const [key, value] of this) {
1578
+ if (!other.has(key))
1579
+ return false;
1580
+ if (value !== peekOf(other, key))
1581
+ return false;
1582
+ }
1583
+ return true;
1584
+ }
1585
+ mapValues(transform) {
1586
+ const result = this.#derived();
1587
+ for (const [key, value] of this)
1588
+ result.set(key, transform(value, key, this));
1589
+ return result;
1590
+ }
1591
+ toReversed() {
1592
+ const result = this.#derived();
1593
+ const entries = [...this];
1594
+ for (let i = entries.length - 1;i >= 0; i--)
1595
+ result.set(entries[i][0], entries[i][1]);
1596
+ return result;
1597
+ }
1598
+ toSorted(comparator) {
1599
+ return this.sorted(comparator);
1600
+ }
1601
+ static groupBy(items, keySelector) {
1602
+ const groups = new Collection;
1603
+ let index = 0;
1604
+ for (const item of items)
1605
+ groups.ensure(keySelector(item, index++), () => []).push(item);
1606
+ return groups;
1607
+ }
1608
+ static combineEntries(entries, combine) {
1609
+ const result = new Collection;
1610
+ for (const [key, value] of entries)
1611
+ result.set(key, result.has(key) ? combine(result.get(key), value, key) : value);
1612
+ return result;
1613
+ }
1491
1614
  tap(fn) {
1492
1615
  fn(this);
1493
1616
  return this;
@@ -1506,6 +1629,13 @@ class Collection extends Map {
1506
1629
  acc = fn(acc, value, key, this);
1507
1630
  return acc;
1508
1631
  }
1632
+ reduceRight(fn, initialValue) {
1633
+ const entries = [...this];
1634
+ let acc = initialValue;
1635
+ for (let i = entries.length - 1;i >= 0; i--)
1636
+ acc = fn(acc, entries[i][1], entries[i][0], this);
1637
+ return acc;
1638
+ }
1509
1639
  sorted(comparator) {
1510
1640
  const decorated = [...this.entries()].map((entry, index) => ({
1511
1641
  entry,
@@ -1516,22 +1646,34 @@ class Collection extends Map {
1516
1646
  const comparison = comparator(x.entry[1], y.entry[1], x.entry[0], y.entry[0]);
1517
1647
  return comparison !== 0 ? comparison : x.index - y.index;
1518
1648
  });
1519
- const result = new Collection;
1649
+ const result = this.#derived();
1520
1650
  for (const { entry } of decorated)
1521
1651
  result.set(entry[0], entry[1]);
1522
1652
  return result;
1523
1653
  }
1524
- random() {
1525
- const arr = [...this.values()];
1526
- if (!arr.length)
1654
+ random(amount) {
1655
+ if (amount !== undefined)
1656
+ return sample([...this.values()], amount);
1657
+ const size = this.size;
1658
+ if (size === 0)
1527
1659
  return;
1528
- return arr[Math.floor(Math.random() * arr.length)];
1660
+ let index = Math.floor(Math.random() * size);
1661
+ for (const value of this.values())
1662
+ if (index-- === 0)
1663
+ return value;
1664
+ return;
1529
1665
  }
1530
- randomKey() {
1531
- const arr = [...this.keys()];
1532
- if (!arr.length)
1666
+ randomKey(amount) {
1667
+ if (amount !== undefined)
1668
+ return sample([...this.keys()], amount);
1669
+ const size = this.size;
1670
+ if (size === 0)
1533
1671
  return;
1534
- return arr[Math.floor(Math.random() * arr.length)];
1672
+ let index = Math.floor(Math.random() * size);
1673
+ for (const key of this.keys())
1674
+ if (index-- === 0)
1675
+ return key;
1676
+ return;
1535
1677
  }
1536
1678
  at(index) {
1537
1679
  const arr = [...this.values()];
@@ -1655,7 +1797,7 @@ class ResourceManager extends Manager {
1655
1797
  // packages/rest/package.json
1656
1798
  var package_default = {
1657
1799
  name: "@lunibee/rest",
1658
- version: "0.2.3",
1800
+ version: "0.2.4",
1659
1801
  type: "module",
1660
1802
  module: "./src/index.ts",
1661
1803
  types: "./src/index.ts",
@@ -1736,7 +1878,7 @@ function kindFromStatus(status) {
1736
1878
  return "client";
1737
1879
  }
1738
1880
  function redactPath(path) {
1739
- return path.replace(/^(\/webhooks\/[^/?]+\/)[^/?]+/, "$1:token").replace(/^(\/interactions\/[^/?]+\/)[^/?]+/, "$1:token");
1881
+ return path.replace(/^(\/webhooks\/[^/?]+\/)[^/?]+/i, "$1:token").replace(/^(\/interactions\/[^/?]+\/)[^/?]+/i, "$1:token");
1740
1882
  }
1741
1883
  var HINTS = {
1742
1884
  50001: "The bot cannot see this resource: check that it is in the guild and has View Channel there.",
@@ -1795,19 +1937,23 @@ async function abortable(promise, signal, path) {
1795
1937
  }
1796
1938
 
1797
1939
  // packages/rest/src/route.ts
1940
+ import { createHash } from "crypto";
1798
1941
  function normalizeRoutePath(path) {
1799
1942
  const queryIndex = path.indexOf("?");
1800
1943
  const routePath = queryIndex === -1 ? path : path.slice(0, queryIndex);
1801
- return routePath.replace(/\/\d+(?=\/|$)/g, "/:id");
1944
+ return redactPath(routePath).replace(/\/\d+(?=\/|$)/g, "/:id");
1802
1945
  }
1803
1946
  function majorParameter(path) {
1804
- const match = /^\/(channels|guilds|webhooks)\/(\d+)(?:\/([^/?]+))?/.exec(path);
1947
+ const match = /^\/(channels|guilds|webhooks)\/(\d+)(?:\/([^/?]+))?/i.exec(path);
1805
1948
  if (!match)
1806
1949
  return "@none";
1807
- if (match[1] === "webhooks" && match[3] !== undefined)
1808
- return `${match[2]}:${match[3]}`;
1950
+ if (match[1].toLowerCase() === "webhooks" && match[3] !== undefined)
1951
+ return `${match[2]}:${tokenDigest(match[3])}`;
1809
1952
  return match[2];
1810
1953
  }
1954
+ function tokenDigest(token) {
1955
+ return createHash("sha256").update(token).digest("hex").slice(0, 16);
1956
+ }
1811
1957
  function scopeBucket(hashOrRoute, major) {
1812
1958
  return `${hashOrRoute}|${major}`;
1813
1959
  }
@@ -2049,6 +2195,9 @@ var Routes = {
2049
2195
  user: () => "/users/@me",
2050
2196
  userById: (userId) => `/users/${snowflake(userId, "User ID")}`,
2051
2197
  guild: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}`,
2198
+ currentUserGuild: (guildId) => `/users/@me/guilds/${snowflake(guildId, "Guild ID")}`,
2199
+ sticker: (stickerId) => `/stickers/${snowflake(stickerId, "Sticker ID")}`,
2200
+ messageReactionUser: (channelId, messageId, emoji, userId) => `${Routes.messageReactions(channelId, messageId, emoji)}/${snowflake(userId, "User ID")}`,
2052
2201
  guildPreview: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/preview`,
2053
2202
  guildActiveThreads: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/threads/active`,
2054
2203
  guildWebhooks: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/webhooks`,
@@ -2310,7 +2459,7 @@ class WebhookClient {
2310
2459
  #rest;
2311
2460
  constructor(options, restOptions) {
2312
2461
  if (options.url) {
2313
- const match = options.url.match(/discord(?:app)?.com\/api\/webhooks\/(\d+)\/([A-Za-z0-9_-]+)/);
2462
+ const match = options.url.match(/^https:\/\/(?:(?:ptb|canary)\.)?discord(?:app)?\.com\/api(?:\/v\d+)?\/webhooks\/(\d{1,20})\/([A-Za-z0-9_-]+)\/?(?:[?#].*)?$/);
2314
2463
  if (!match)
2315
2464
  throw new Error("Invalid Discord webhook URL format.");
2316
2465
  this.id = match[1];
@@ -2325,13 +2474,20 @@ class WebhookClient {
2325
2474
  }
2326
2475
  async send(options) {
2327
2476
  const payload = typeof options === "string" ? { content: options } : options;
2328
- const { thread_id, ...body } = payload;
2329
- const query = thread_id ? `?thread_id=${thread_id}&wait=true` : `?wait=true`;
2477
+ const { thread_id, files, ...body } = payload;
2478
+ const params = new URLSearchParams({ wait: "true" });
2479
+ if (thread_id)
2480
+ params.set("thread_id", String(thread_id));
2481
+ const query = `?${params}`;
2330
2482
  const formattedEmbeds = body.embeds?.map((e) => ("toJSON" in e) ? e.toJSON() : e);
2331
- return this.#rest.post(`${Routes.webhook(this.id, this.token)}${query}`, {
2483
+ const formattedComponents = body.components?.map((c) => ("toJSON" in c) ? c.toJSON() : c);
2484
+ const path = `${Routes.webhook(this.id, this.token)}${query}`;
2485
+ const json = {
2332
2486
  ...body,
2333
- embeds: formattedEmbeds
2334
- });
2487
+ embeds: formattedEmbeds,
2488
+ components: formattedComponents
2489
+ };
2490
+ return files?.length ? this.#rest.postWithFiles(path, json, files) : this.#rest.post(path, json);
2335
2491
  }
2336
2492
  async editMessage(messageId, options) {
2337
2493
  const payload = typeof options === "string" ? { content: options } : options;
@@ -2346,6 +2502,22 @@ class WebhookClient {
2346
2502
  var LIBRARY_VERSION = package_default.version;
2347
2503
  var LIBRARY_URL = "https://github.com/Ekretos/lunibee";
2348
2504
  var USER_AGENT = `DiscordBot (${LIBRARY_URL}, ${LIBRARY_VERSION})`;
2505
+ function assertSafePath(path) {
2506
+ const end = path.search(/[?#]/);
2507
+ const pathname = end === -1 ? path : path.slice(0, end);
2508
+ if (pathname.includes("\\"))
2509
+ throw new TypeError("REST paths must not contain backslashes.");
2510
+ for (const segment of pathname.split("/")) {
2511
+ let decoded;
2512
+ try {
2513
+ decoded = decodeURIComponent(segment);
2514
+ } catch {
2515
+ throw new TypeError("REST path has malformed percent-encoding.");
2516
+ }
2517
+ if (decoded === "." || decoded === "..")
2518
+ throw new TypeError("REST paths must not contain '.' or '..' segments.");
2519
+ }
2520
+ }
2349
2521
  var REQUEST_DATA_KEYS = new Set([
2350
2522
  "body",
2351
2523
  "files",
@@ -2430,6 +2602,7 @@ class REST {
2430
2602
  throw new TypeError("REST method is required.");
2431
2603
  if (!path.startsWith("/"))
2432
2604
  throw new TypeError("REST paths must start with '/'.");
2605
+ assertSafePath(path);
2433
2606
  const route = createRouteKey(method, path);
2434
2607
  const files = options.files;
2435
2608
  if (files && files.length > 0 && !(body instanceof FormData))
@@ -2517,13 +2690,19 @@ class REST {
2517
2690
  #headers(body, options) {
2518
2691
  const isFormData = typeof FormData !== "undefined" && body instanceof FormData;
2519
2692
  const headers = { ...options.headers };
2693
+ const set = (name, value) => {
2694
+ for (const key of Object.keys(headers))
2695
+ if (key.toLowerCase() === name.toLowerCase())
2696
+ delete headers[key];
2697
+ headers[name] = value;
2698
+ };
2520
2699
  if (options.auth !== false && this.#token)
2521
- headers["Authorization"] = `Bot ${this.#token}`;
2522
- headers["User-Agent"] = USER_AGENT;
2700
+ set("Authorization", `Bot ${this.#token}`);
2701
+ set("User-Agent", USER_AGENT);
2523
2702
  if (options.reason !== undefined)
2524
- headers["X-Audit-Log-Reason"] = encodeURIComponent(options.reason);
2703
+ set("X-Audit-Log-Reason", encodeURIComponent(options.reason));
2525
2704
  if (!isFormData)
2526
- headers["Content-Type"] = "application/json";
2705
+ set("Content-Type", "application/json");
2527
2706
  return headers;
2528
2707
  }
2529
2708
  #encodeBody(body) {
@@ -2599,7 +2778,7 @@ function cdnURL(path, hash, options = {}) {
2599
2778
  const isAnimated = hash.startsWith("a_") && !options.forceStatic;
2600
2779
  const ext = options.extension ?? (isAnimated ? "gif" : "png");
2601
2780
  const size = options.size ? `?size=${options.size}` : "";
2602
- return `${CDN_BASE}${path}/${hash}.${ext}${size}`;
2781
+ return `${CDN_BASE}${path}/${encodeURIComponent(hash)}.${ext}${size}`;
2603
2782
  }
2604
2783
 
2605
2784
  class User extends BaseStructure {
@@ -2889,10 +3068,10 @@ class GuildMember {
2889
3068
  get permissions() {
2890
3069
  if (this.#suppliedPermissions)
2891
3070
  return this.#suppliedPermissions;
2892
- return new PermissionsBitField(this.#context?.memberPermissions?.(this.guildId, this.user.id, this.roleIds) ?? 0n);
3071
+ return new PermissionsBitField(this.#context?.memberPermissions?.(this.guildId, this.user.id, this.roleIds, undefined, this.timedOutUntil) ?? 0n);
2893
3072
  }
2894
3073
  permissionsIn(channelId) {
2895
- const computed = this.#context?.memberPermissions?.(this.guildId, this.user.id, this.roleIds, channelId);
3074
+ const computed = this.#context?.memberPermissions?.(this.guildId, this.user.id, this.roleIds, channelId, this.timedOutUntil);
2896
3075
  return computed ? new PermissionsBitField(computed) : null;
2897
3076
  }
2898
3077
  #action(name) {
@@ -4343,7 +4522,7 @@ class UserManager extends ResourceManager {
4343
4522
  return this.upsert(new User(data));
4344
4523
  }
4345
4524
  async leaveGuild(guildId) {
4346
- await this.#rest.delete(`/users/@me/guilds/${guildId}`);
4525
+ await this.#rest.delete(Routes.currentUserGuild(guildId));
4347
4526
  }
4348
4527
  async createDM(userId) {
4349
4528
  return this.#rest.post("/users/@me/channels", {
@@ -4632,20 +4811,15 @@ class RoleManager extends ResourceManager {
4632
4811
  }
4633
4812
  async create(options) {
4634
4813
  const { reason, ...payload } = options;
4635
- const data = await this.#rest.post(Routes.guildRoles(this.guildId), {
4636
- ...payload,
4637
- permissions: payload.permissions !== undefined ? String(payload.permissions) : undefined
4638
- }, { reason });
4639
- const role = new Role(data);
4640
- this.set(role.id, role);
4641
- return role;
4814
+ const data = await this.#rest.post(Routes.guildRoles(this.guildId), rolePayload(payload), { reason });
4815
+ return this.#store(data);
4642
4816
  }
4643
4817
  async edit(roleId, options) {
4644
4818
  const { reason, ...payload } = options;
4645
- const data = await this.#rest.patch(Routes.guildRole(this.guildId, roleId), {
4646
- ...payload,
4647
- permissions: payload.permissions !== undefined ? String(payload.permissions) : undefined
4648
- }, { reason });
4819
+ const data = await this.#rest.patch(Routes.guildRole(this.guildId, roleId), rolePayload(payload), { reason });
4820
+ return this.#store(data);
4821
+ }
4822
+ #store(data) {
4649
4823
  const role = new Role(data);
4650
4824
  this.set(role.id, role);
4651
4825
  return role;
@@ -4668,6 +4842,13 @@ class RoleManager extends ResourceManager {
4668
4842
  return this.remove(roleId);
4669
4843
  }
4670
4844
  }
4845
+ function rolePayload(options) {
4846
+ const { permissions, ...rest } = options;
4847
+ return {
4848
+ ...rest,
4849
+ permissions: permissions !== undefined ? String(permissions) : undefined
4850
+ };
4851
+ }
4671
4852
 
4672
4853
  // packages/managers/src/guild-resources.ts
4673
4854
  function withQuery2(path, params) {
@@ -5304,7 +5485,7 @@ class ChannelManager extends Manager {
5304
5485
  await this.#rest.delete(`${Routes.messageReactions(channelId, messageId, emoji)}/@me`);
5305
5486
  }
5306
5487
  async removeReaction(channelId, messageId, emoji, userId) {
5307
- await this.#rest.delete(`${Routes.messageReactions(channelId, messageId, emoji)}/${userId}`);
5488
+ await this.#rest.delete(Routes.messageReactionUser(channelId, messageId, emoji, userId));
5308
5489
  }
5309
5490
  async removeAllReactions(channelId, messageId) {
5310
5491
  await this.#rest.delete(Routes.messageReactionsAll(channelId, messageId));
@@ -5427,7 +5608,26 @@ class GatewaySession {
5427
5608
  return resume ? { type: "resume", ...resume } : { type: "identify" };
5428
5609
  }
5429
5610
  connectURL(fallback) {
5430
- return this.resumeInfo()?.resumeURL ?? fallback;
5611
+ const resume = this.resumeInfo()?.resumeURL;
5612
+ return resume !== undefined && isTrustedGatewayURL(resume, fallback) ? resume : fallback;
5613
+ }
5614
+ }
5615
+ function isTrustedGatewayURL(url, fallback) {
5616
+ let parsed;
5617
+ try {
5618
+ parsed = new URL(url);
5619
+ } catch {
5620
+ return false;
5621
+ }
5622
+ if (parsed.protocol !== "wss:" || parsed.username || parsed.password)
5623
+ return false;
5624
+ const host = parsed.hostname.toLowerCase();
5625
+ if (host === "discord.gg" || host.endsWith(".discord.gg"))
5626
+ return true;
5627
+ try {
5628
+ return host === new URL(fallback).hostname.toLowerCase();
5629
+ } catch {
5630
+ return false;
5431
5631
  }
5432
5632
  }
5433
5633
 
@@ -5703,12 +5903,15 @@ class PlainTextDecoder {
5703
5903
 
5704
5904
  class ZlibStreamDecoder {
5705
5905
  #create;
5906
+ #maxFrameBytes;
5706
5907
  #inflate;
5707
5908
  #chunks = [];
5909
+ #size = 0;
5708
5910
  #failure;
5709
5911
  #pendingReject;
5710
- constructor(create = () => createInflate()) {
5912
+ constructor(create = () => createInflate(), maxFrameBytes = 64 * 1024 * 1024) {
5711
5913
  this.#create = create;
5914
+ this.#maxFrameBytes = maxFrameBytes;
5712
5915
  }
5713
5916
  push(data) {
5714
5917
  if (typeof data === "string")
@@ -5727,6 +5930,7 @@ class ZlibStreamDecoder {
5727
5930
  await this.#awaiting((settle) => inflate.flush(zlibConstants.Z_SYNC_FLUSH, () => settle()));
5728
5931
  const parts = this.#chunks;
5729
5932
  this.#chunks = [];
5933
+ this.#size = 0;
5730
5934
  if (parts.length === 0)
5731
5935
  return [];
5732
5936
  const total = parts.reduce((size, part) => size + part.length, 0);
@@ -5742,6 +5946,7 @@ class ZlibStreamDecoder {
5742
5946
  const inflate = this.#inflate;
5743
5947
  this.#inflate = undefined;
5744
5948
  this.#chunks = [];
5949
+ this.#size = 0;
5745
5950
  this.#failure = undefined;
5746
5951
  this.#pendingReject = undefined;
5747
5952
  if (!inflate)
@@ -5769,7 +5974,17 @@ class ZlibStreamDecoder {
5769
5974
  }
5770
5975
  #open() {
5771
5976
  const inflate = this.#create();
5772
- inflate.on("data", (chunk) => this.#chunks.push(chunk));
5977
+ inflate.on("data", (chunk) => {
5978
+ if (this.#failure)
5979
+ return;
5980
+ this.#size += chunk.length;
5981
+ if (this.#size > this.#maxFrameBytes) {
5982
+ this.#chunks = [];
5983
+ inflate.emit("error", new Error(`Gateway frame inflated past ${this.#maxFrameBytes} bytes.`));
5984
+ return;
5985
+ }
5986
+ this.#chunks.push(chunk);
5987
+ });
5773
5988
  inflate.on("error", (error) => {
5774
5989
  this.#failure = error;
5775
5990
  const reject = this.#pendingReject;
@@ -6012,9 +6227,9 @@ function classifyPayload(payload) {
6012
6227
  }
6013
6228
  function identifyPayload(options) {
6014
6229
  const props = options.properties ?? {};
6015
- const os = props.os ?? "Android";
6016
- const browser = props.browser ?? "Discord Android";
6017
- const device = props.device ?? "Discord Android";
6230
+ const os = props.os ?? process.platform;
6231
+ const browser = props.browser ?? "Lunibee";
6232
+ const device = props.device ?? "Lunibee";
6018
6233
  return {
6019
6234
  op: GatewayOpcodes.Identify,
6020
6235
  d: {
@@ -6131,9 +6346,9 @@ class Gateway {
6131
6346
  heartbeatAckTimeout: 1e4,
6132
6347
  zombieTimeout: 30000,
6133
6348
  properties: {
6134
- os: "Android",
6135
- browser: "Discord Android",
6136
- device: "Discord Android"
6349
+ os: process.platform,
6350
+ browser: "Lunibee",
6351
+ device: "Lunibee"
6137
6352
  },
6138
6353
  presence: {
6139
6354
  status: "online",
@@ -6449,14 +6664,12 @@ class Gateway {
6449
6664
 
6450
6665
  // packages/core/src/index.ts
6451
6666
  class EventEmitter2 {
6452
- #listeners = new Map;
6667
+ #listeners = {};
6668
+ redactSecrets = (text) => text;
6453
6669
  on(event, listener) {
6454
6670
  if (typeof listener !== "function")
6455
6671
  throw new TypeError("Event listener must be a function.");
6456
- let listeners = this.#listeners.get(event);
6457
- if (!listeners)
6458
- this.#listeners.set(event, listeners = new Set);
6459
- listeners.add(listener);
6672
+ (this.#listeners[event] ??= new Set).add(listener);
6460
6673
  return this;
6461
6674
  }
6462
6675
  once(event, listener) {
@@ -6467,7 +6680,7 @@ class EventEmitter2 {
6467
6680
  return this.on(event, wrapped);
6468
6681
  }
6469
6682
  off(event, listener) {
6470
- this.#listeners.get(event)?.delete(listener);
6683
+ this.#listeners[event]?.delete(listener);
6471
6684
  return this;
6472
6685
  }
6473
6686
  removeListener(event, listener) {
@@ -6475,13 +6688,13 @@ class EventEmitter2 {
6475
6688
  }
6476
6689
  removeAllListeners(event) {
6477
6690
  if (event === undefined)
6478
- this.#listeners.clear();
6691
+ this.#listeners = {};
6479
6692
  else
6480
- this.#listeners.delete(event);
6693
+ delete this.#listeners[event];
6481
6694
  return this;
6482
6695
  }
6483
6696
  emit(event, ...args) {
6484
- const listeners = this.#listeners.get(event);
6697
+ const listeners = this.#listeners[event];
6485
6698
  if (!listeners?.size)
6486
6699
  return false;
6487
6700
  for (const listener of [...listeners]) {
@@ -6497,28 +6710,27 @@ class EventEmitter2 {
6497
6710
  }
6498
6711
  #handleError(event, error) {
6499
6712
  const normalized = error instanceof Error ? error : new Error(String(error), { cause: error });
6500
- const listeners = event === "error" /* Error */ ? [] : [
6501
- ...this.#listeners.get("error" /* Error */) ?? []
6502
- ];
6713
+ const errorListeners = this.#listeners["error" /* Error */];
6714
+ const listeners = event === "error" /* Error */ ? [] : [...errorListeners ?? []];
6503
6715
  if (listeners.length === 0)
6504
- return warnListenerError(event, normalized);
6716
+ return warnListenerError(event, normalized, this.redactSecrets);
6505
6717
  for (const listener of listeners) {
6506
6718
  try {
6507
6719
  const result = listener(normalized);
6508
6720
  if (result && typeof result.then === "function")
6509
- Promise.resolve(result).catch((failure) => warnListenerError("error" /* Error */, failure));
6721
+ Promise.resolve(result).catch((failure) => warnListenerError("error" /* Error */, failure, this.redactSecrets));
6510
6722
  } catch (failure) {
6511
- warnListenerError("error" /* Error */, failure);
6723
+ warnListenerError("error" /* Error */, failure, this.redactSecrets);
6512
6724
  }
6513
6725
  }
6514
6726
  }
6515
6727
  }
6516
- function warnListenerError(event, error) {
6728
+ function warnListenerError(event, error, redact = (text) => text) {
6517
6729
  const failure = error instanceof Error ? error : new Error(String(error));
6518
- process.emitWarning(`A "${String(event)}" listener threw and no error listener handled it: ${failure.message}`, {
6730
+ process.emitWarning(redact(`A "${String(event)}" listener threw and no error listener handled it: ${failure.message}`), {
6519
6731
  type: "LunibeeWarning",
6520
6732
  code: "LUNIBEE_UNHANDLED_LISTENER_ERROR",
6521
- detail: failure.stack
6733
+ detail: failure.stack === undefined ? undefined : redact(failure.stack)
6522
6734
  });
6523
6735
  }
6524
6736
 
@@ -6540,6 +6752,10 @@ class Client extends EventEmitter2 {
6540
6752
  user;
6541
6753
  readyAt;
6542
6754
  state = "idle";
6755
+ redactSecrets = (text) => {
6756
+ const token = this.options.token;
6757
+ return token && token.length >= 8 ? text.split(token).join("[token]") : text;
6758
+ };
6543
6759
  get token() {
6544
6760
  return this.state === "destroyed" ? null : this.options.token ?? null;
6545
6761
  }
@@ -6586,7 +6802,22 @@ class Client extends EventEmitter2 {
6586
6802
  this.stageInstances = new StageInstanceManager(this.rest);
6587
6803
  const placeholderAppCommands = new ApplicationCommandManager(this.rest, "0");
6588
6804
  this.application = { commands: placeholderAppCommands };
6589
- this.#resourceContext = {
6805
+ this.#resourceContext = this.#createResourceContext();
6806
+ this.guilds.attachContext(this.#resourceContext);
6807
+ this.#gateway = new Gateway({
6808
+ token: options.token,
6809
+ intents: options.intents,
6810
+ ...options.gateway
6811
+ });
6812
+ this.#wireLifecycle();
6813
+ this.#wireMessages();
6814
+ this.#wireGuilds();
6815
+ this.#wireGuildFeatures();
6816
+ this.#wireChannels();
6817
+ this.#wireMisc();
6818
+ }
6819
+ #createResourceContext() {
6820
+ return {
6590
6821
  sendMessage: (channelId, options) => this.channels.send(channelId, options),
6591
6822
  editMessage: (channelId, messageId, options) => this.channels.editMessage(channelId, messageId, options),
6592
6823
  deleteMessage: (channelId, messageId, reason) => this.channels.deleteMessage(channelId, messageId, reason),
@@ -6600,7 +6831,7 @@ class Client extends EventEmitter2 {
6600
6831
  pinMessage: (channelId, messageId, reason) => this.channels.pinMessage(channelId, messageId, reason),
6601
6832
  unpinMessage: (channelId, messageId, reason) => this.channels.unpinMessage(channelId, messageId, reason),
6602
6833
  collectInteractions: (options) => this.createCollector("interactionCreate" /* InteractionCreate */, options),
6603
- memberPermissions: (guildId, memberId, roleIds, channelId) => this.#memberPermissions(guildId, memberId, roleIds, channelId),
6834
+ memberPermissions: (guildId, memberId, roleIds, channelId, timedOutUntil) => this.#memberPermissions(guildId, memberId, roleIds, channelId, timedOutUntil),
6604
6835
  kickMember: (guildId, userId, reason) => this.guilds.members(guildId).kick(userId, reason),
6605
6836
  banMember: (guildId, userId, options) => this.guilds.members(guildId).ban(userId, options),
6606
6837
  editMember: (guildId, userId, options, reason) => this.guilds.members(guildId).edit(userId, options, reason),
@@ -6623,12 +6854,8 @@ class Client extends EventEmitter2 {
6623
6854
  return this.channels.permissionOverwrites(channelId).update(targetId, bits, options);
6624
6855
  }
6625
6856
  };
6626
- this.guilds.attachContext(this.#resourceContext);
6627
- this.#gateway = new Gateway({
6628
- token: options.token,
6629
- intents: options.intents,
6630
- ...options.gateway
6631
- });
6857
+ }
6858
+ #wireLifecycle() {
6632
6859
  this.#gateway.on("READY", (data) => {
6633
6860
  const ready = data;
6634
6861
  this.user = ready.user;
@@ -6654,6 +6881,8 @@ class Client extends EventEmitter2 {
6654
6881
  this.state = "idle";
6655
6882
  this.emit("close" /* Close */, data);
6656
6883
  });
6884
+ }
6885
+ #wireMessages() {
6657
6886
  this.#gateway.on("MESSAGE_CREATE", (data) => {
6658
6887
  const payload = data;
6659
6888
  const message = new Message(payload, this.#resourceContext);
@@ -6701,6 +6930,8 @@ class Client extends EventEmitter2 {
6701
6930
  this.#gateway.on("MESSAGE_REACTION_REMOVE_EMOJI", (data) => this.emit("messageReactionRemoveEmoji" /* MessageReactionRemoveEmoji */, data));
6702
6931
  this.#gateway.on("MESSAGE_POLL_VOTE_ADD", (data) => this.emit("messagePollVoteAdd" /* MessagePollVoteAdd */, data));
6703
6932
  this.#gateway.on("MESSAGE_POLL_VOTE_REMOVE", (data) => this.emit("messagePollVoteRemove" /* MessagePollVoteRemove */, data));
6933
+ }
6934
+ #wireGuilds() {
6704
6935
  this.#gateway.on("GUILD_CREATE", (data) => {
6705
6936
  const payload = data;
6706
6937
  if (payload.unavailable) {
@@ -6801,6 +7032,8 @@ class Client extends EventEmitter2 {
6801
7032
  roles.delete(event.role_id);
6802
7033
  this.emit("guildRoleDelete" /* GuildRoleDelete */, event, removed);
6803
7034
  });
7035
+ }
7036
+ #wireGuildFeatures() {
6804
7037
  this.#gateway.on("GUILD_EMOJIS_UPDATE", (data) => {
6805
7038
  const event = data;
6806
7039
  let previous = null;
@@ -6897,6 +7130,8 @@ class Client extends EventEmitter2 {
6897
7130
  this.emit("autoModerationRuleDelete" /* AutoModerationRuleDelete */, rule);
6898
7131
  });
6899
7132
  this.#gateway.on("AUTO_MODERATION_ACTION_EXECUTION", (data) => this.emit("autoModerationActionExecution" /* AutoModerationActionExecution */, data));
7133
+ }
7134
+ #wireChannels() {
6900
7135
  this.#gateway.on("CHANNEL_CREATE", (data) => {
6901
7136
  const channel = this.channels.upsert(data);
6902
7137
  this.emit("channelCreate" /* ChannelCreate */, channel);
@@ -6964,6 +7199,8 @@ class Client extends EventEmitter2 {
6964
7199
  this.emit("inviteDelete" /* InviteDelete */, invite);
6965
7200
  });
6966
7201
  this.#gateway.on("WEBHOOKS_UPDATE", (data) => this.emit("webhooksUpdate" /* WebhooksUpdate */, data));
7202
+ }
7203
+ #wireMisc() {
6967
7204
  this.#gateway.on("VOICE_STATE_UPDATE", (data) => {
6968
7205
  const state = data;
6969
7206
  if (state.guild_id)
@@ -7039,7 +7276,7 @@ class Client extends EventEmitter2 {
7039
7276
  get resourceContext() {
7040
7277
  return this.#resourceContext;
7041
7278
  }
7042
- #memberPermissions(guildId, memberId, roleIds, channelId) {
7279
+ #memberPermissions(guildId, memberId, roleIds, channelId, timedOutUntil) {
7043
7280
  const guild = this.guilds.get(guildId);
7044
7281
  if (!guild)
7045
7282
  return null;
@@ -7056,7 +7293,8 @@ class Client extends EventEmitter2 {
7056
7293
  memberId,
7057
7294
  memberRoleIds: [...roleIds],
7058
7295
  roles: this.guilds.roles(guildId).values(),
7059
- overwrites: channel?.permissionOverwrites
7296
+ overwrites: channel?.permissionOverwrites,
7297
+ timedOutUntil
7060
7298
  });
7061
7299
  }
7062
7300
  permissionsFor(memberId, guildOrChannelId) {
@@ -7077,7 +7315,8 @@ class Client extends EventEmitter2 {
7077
7315
  memberId,
7078
7316
  memberRoleIds: member.roleIds,
7079
7317
  roles: this.guilds.roles(guildId).values(),
7080
- overwrites: channel?.permissionOverwrites
7318
+ overwrites: channel?.permissionOverwrites,
7319
+ timedOutUntil: member.timedOutUntil
7081
7320
  });
7082
7321
  }
7083
7322
  fetchDefaultSoundboardSounds() {
@@ -7125,10 +7364,10 @@ class Client extends EventEmitter2 {
7125
7364
  return Promise.reject(new Error("Client is unauthenticated."));
7126
7365
  return this.rest.delete(Routes.interactionOriginalResponse(this.user.id, token));
7127
7366
  }
7128
- followUpInteraction(token, data) {
7367
+ async followUpInteraction(token, data) {
7129
7368
  if (!this.user)
7130
7369
  return Promise.reject(new Error("Client is unauthenticated."));
7131
- return this.rest.post(`/webhooks/${this.user.id}/${token}`, toRequest(data, this.options.allowedMentions));
7370
+ return this.rest.post(Routes.webhook(this.user.id, token), toRequest(data, this.options.allowedMentions));
7132
7371
  }
7133
7372
  interactionWebhookMessage(method, applicationId, token, messageId, data) {
7134
7373
  const path = messageId === "@original" ? Routes.interactionOriginalResponse(applicationId, token) : Routes.webhookMessage(applicationId, token, messageId);
@@ -7138,11 +7377,11 @@ class Client extends EventEmitter2 {
7138
7377
  return this.rest.patch(path, data ? toRequest(data, this.options.allowedMentions) : data);
7139
7378
  return this.rest.delete(path);
7140
7379
  }
7141
- fetchWebhook(id, token) {
7142
- return this.rest.get(token ? `/webhooks/${id}/${token}` : `/webhooks/${id}`);
7380
+ async fetchWebhook(id, token) {
7381
+ return this.rest.get(Routes.webhook(id, token));
7143
7382
  }
7144
- fetchGuildPreview(guildId) {
7145
- return this.rest.get(`/guilds/${guildId}/preview`);
7383
+ async fetchGuildPreview(guildId) {
7384
+ return this.rest.get(Routes.guildPreview(guildId));
7146
7385
  }
7147
7386
  fetchVoiceRegions() {
7148
7387
  return this.rest.get("/voice/regions");
@@ -7156,8 +7395,8 @@ class Client extends EventEmitter2 {
7156
7395
  const qs = query.toString();
7157
7396
  return this.rest.get(`/invites/${encodeURIComponent(code)}${qs ? `?${qs}` : ""}`);
7158
7397
  }
7159
- fetchSticker(id) {
7160
- return this.rest.get(`/stickers/${id}`);
7398
+ async fetchSticker(id) {
7399
+ return this.rest.get(Routes.sticker(id));
7161
7400
  }
7162
7401
  fetchPremiumStickerPacks() {
7163
7402
  return this.rest.get(`/sticker-packs`);
@@ -7217,13 +7456,17 @@ function inlineCode(text) {
7217
7456
  return `\`${text}\``;
7218
7457
  }
7219
7458
  function codeBlock(text, language = "") {
7220
- return `\`\`\`${language}
7221
- ${text}
7459
+ const safe = text.replace(/```/g, "`\u200B``");
7460
+ const lang = language.replace(/[^\w+#.-]/g, "");
7461
+ return `\`\`\`${lang}
7462
+ ${safe}
7222
7463
  \`\`\``;
7223
7464
  }
7224
7465
  function link(label, url, title) {
7225
- const titlePart = title ? ` "${title}"` : "";
7226
- return `[${label}](${url}${titlePart})`;
7466
+ const text = label.replace(/[[\]\\]/g, "\\$&").replace(/\n/g, " ");
7467
+ const target = url.replace(/[()\s"]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase().padStart(2, "0")}`);
7468
+ const titlePart = title ? ` "${title.replace(/["\n]/g, "")}"` : "";
7469
+ return `[${text}](${target}${titlePart})`;
7227
7470
  }
7228
7471
  function blockQuote(text) {
7229
7472
  return text.split(`
@@ -7262,14 +7505,9 @@ function validateSnowflake(id, field) {
7262
7505
  }
7263
7506
  // packages/handlers/src/index.ts
7264
7507
  class HandlerRegistry {
7265
- #handlers = new Map;
7508
+ #handlers = {};
7266
7509
  on(event, handler) {
7267
- let handlers = this.#handlers.get(event);
7268
- if (!handlers) {
7269
- handlers = new Set;
7270
- this.#handlers.set(event, handlers);
7271
- }
7272
- handlers.add(handler);
7510
+ (this.#handlers[event] ??= new Set).add(handler);
7273
7511
  return this;
7274
7512
  }
7275
7513
  once(event, handler) {
@@ -7280,11 +7518,11 @@ class HandlerRegistry {
7280
7518
  return this.on(event, wrapped);
7281
7519
  }
7282
7520
  off(event, handler) {
7283
- this.#handlers.get(event)?.delete(handler);
7521
+ this.#handlers[event]?.delete(handler);
7284
7522
  return this;
7285
7523
  }
7286
7524
  async dispatch(event, ...args) {
7287
- for (const handler of this.#handlers.get(event) ?? [])
7525
+ for (const handler of this.#handlers[event] ?? [])
7288
7526
  await handler(...args);
7289
7527
  }
7290
7528
  emit(event, ...args) {
@@ -7294,7 +7532,7 @@ class HandlerRegistry {
7294
7532
  // packages/sharding/package.json
7295
7533
  var package_default2 = {
7296
7534
  name: "@lunibee/sharding",
7297
- version: "0.2.3",
7535
+ version: "0.2.4",
7298
7536
  type: "module",
7299
7537
  module: "./src/index.ts",
7300
7538
  types: "./src/index.ts",
@@ -8039,6 +8277,9 @@ var SpeakingFlags = {
8039
8277
  Soundshare: 2,
8040
8278
  Priority: 4
8041
8279
  };
8280
+ function listenerSet(sets, event) {
8281
+ return sets[event] ??= new Set;
8282
+ }
8042
8283
 
8043
8284
  class VoiceConnection {
8044
8285
  state = "disconnected" /* Disconnected */;
@@ -8048,7 +8289,7 @@ class VoiceConnection {
8048
8289
  selfDeaf;
8049
8290
  gateway;
8050
8291
  udp;
8051
- #listeners = new Map;
8292
+ #listeners = {};
8052
8293
  receiver;
8053
8294
  constructor(options) {
8054
8295
  const resolved = typeof options === "string" ? { guildId: options } : options;
@@ -8064,14 +8305,11 @@ class VoiceConnection {
8064
8305
  on(event, listener) {
8065
8306
  if (typeof listener !== "function")
8066
8307
  throw new TypeError("Voice listener must be a function.");
8067
- let listeners = this.#listeners.get(event);
8068
- if (!listeners)
8069
- this.#listeners.set(event, listeners = new Set);
8070
- listeners.add(listener);
8308
+ listenerSet(this.#listeners, event).add(listener);
8071
8309
  return this;
8072
8310
  }
8073
8311
  off(event, listener) {
8074
- this.#listeners.get(event)?.delete(listener);
8312
+ this.#listeners[event]?.delete(listener);
8075
8313
  return this;
8076
8314
  }
8077
8315
  attachTransports(gateway, udp) {
@@ -8114,7 +8352,7 @@ class VoiceConnection {
8114
8352
  this.receiver.close();
8115
8353
  this.channelId = undefined;
8116
8354
  this.#transition("destroyed" /* Destroyed */);
8117
- this.#listeners.clear();
8355
+ this.#listeners = {};
8118
8356
  }
8119
8357
  setChannel(channelId) {
8120
8358
  this.assertUsable();
@@ -8165,7 +8403,7 @@ class VoiceConnection {
8165
8403
  this.state = next;
8166
8404
  if (previous === next)
8167
8405
  return;
8168
- for (const listener of this.#listeners.get("stateChange") ?? []) {
8406
+ for (const listener of this.#listeners.stateChange ?? []) {
8169
8407
  try {
8170
8408
  listener(next, previous);
8171
8409
  } catch (error) {
@@ -8178,7 +8416,7 @@ class VoiceConnection {
8178
8416
  }
8179
8417
  }
8180
8418
  #emit(event, ...args) {
8181
- for (const listener of this.#listeners.get(event) ?? []) {
8419
+ for (const listener of this.#listeners[event] ?? []) {
8182
8420
  try {
8183
8421
  listener(...args);
8184
8422
  } catch {}
@@ -8205,7 +8443,7 @@ class AudioPlayer {
8205
8443
  #stream;
8206
8444
  #reader;
8207
8445
  #resumeSignal;
8208
- #listeners = new Map;
8446
+ #playerListeners = {};
8209
8447
  get state() {
8210
8448
  return this.#state;
8211
8449
  }
@@ -8250,15 +8488,11 @@ class AudioPlayer {
8250
8488
  }
8251
8489
  }
8252
8490
  on(event, listener) {
8253
- let set = this.#listeners.get(event);
8254
- if (!set) {
8255
- this.#listeners.set(event, set = new Set);
8256
- }
8257
- set.add(listener);
8491
+ listenerSet(this.#playerListeners, event).add(listener);
8258
8492
  return this;
8259
8493
  }
8260
8494
  off(event, listener) {
8261
- this.#listeners.get(event)?.delete(listener);
8495
+ this.#playerListeners[event]?.delete(listener);
8262
8496
  return this;
8263
8497
  }
8264
8498
  onChunk(chunk) {}
@@ -8300,7 +8534,7 @@ class AudioPlayer {
8300
8534
  this.#emit("error", err instanceof Error ? err : new VoiceError(String(err)));
8301
8535
  }
8302
8536
  #emit(event, ...args) {
8303
- for (const listener of this.#listeners.get(event) ?? []) {
8537
+ for (const listener of this.#playerListeners[event] ?? []) {
8304
8538
  try {
8305
8539
  listener(...args);
8306
8540
  } catch {}
@@ -8562,24 +8796,6 @@ function url(value, field) {
8562
8796
  }
8563
8797
  var EmbedBuilder = CreateEmbed;
8564
8798
  // packages/builders/src/components.ts
8565
- var ComponentEnum = {
8566
- ActionRow: 1,
8567
- Button: 2,
8568
- StringSelect: 3,
8569
- TextInput: 4,
8570
- UserSelect: 5,
8571
- RoleSelect: 6,
8572
- MentionableSelect: 7,
8573
- ChannelSelect: 8,
8574
- Section: 9,
8575
- TextDisplay: 10,
8576
- Thumbnail: 11,
8577
- MediaGallery: 12,
8578
- File: 13,
8579
- Separator: 14,
8580
- ContentInventoryEntry: 16,
8581
- Container: 17
8582
- };
8583
8799
  var TextInputType = { Short: 1, Paragraph: 2 };
8584
8800
 
8585
8801
  class CreateActionRow {
@@ -8607,38 +8823,50 @@ class CreateActionRow {
8607
8823
  }
8608
8824
  }
8609
8825
 
8610
- class CreateStringSelect {
8611
- #data = {
8612
- type: ComponentEnum.StringSelect
8613
- };
8826
+ class CreateSelectMenu {
8827
+ #select;
8828
+ constructor(data) {
8829
+ this.#select = data;
8830
+ }
8614
8831
  setCustomId(value) {
8615
8832
  validateText(value, 100, "Component custom ID");
8616
- this.#data.custom_id = value;
8833
+ this.#select.custom_id = value;
8617
8834
  return this;
8618
8835
  }
8619
8836
  setPlaceholder(value) {
8620
8837
  validateText(value, 150, "Component placeholder");
8621
- this.#data.placeholder = value;
8838
+ this.#select.placeholder = value;
8622
8839
  return this;
8623
8840
  }
8624
8841
  setMinValues(value) {
8625
8842
  validateCount(value, "min_values", 0);
8626
- this.#data.min_values = value;
8843
+ this.#select.min_values = value;
8627
8844
  return this;
8628
8845
  }
8629
8846
  setMaxValues(value) {
8630
8847
  validateCount(value, "max_values", 1);
8631
- this.#data.max_values = value;
8848
+ this.#select.max_values = value;
8632
8849
  return this;
8633
8850
  }
8634
8851
  setRequired(value = true) {
8635
- this.#data.required = value;
8852
+ this.#select.required = value;
8636
8853
  return this;
8637
8854
  }
8638
8855
  setDisabled(value = true) {
8639
- this.#data.disabled = value;
8856
+ this.#select.disabled = value;
8640
8857
  return this;
8641
8858
  }
8859
+ }
8860
+
8861
+ class CreateStringSelect extends CreateSelectMenu {
8862
+ #data;
8863
+ constructor() {
8864
+ const data = {
8865
+ type: ComponentEnum.StringSelect
8866
+ };
8867
+ super(data);
8868
+ this.#data = data;
8869
+ }
8642
8870
  addOptions(...options) {
8643
8871
  if (!options.length)
8644
8872
  throw new TypeError("At least one select option is required.");
@@ -8754,40 +8982,14 @@ class CreateButton {
8754
8982
  }
8755
8983
  }
8756
8984
 
8757
- class CreateEntitySelect {
8985
+ class CreateEntitySelect extends CreateSelectMenu {
8758
8986
  #data;
8759
8987
  constructor(type) {
8760
8988
  if (type !== ComponentEnum.UserSelect && type !== ComponentEnum.RoleSelect && type !== ComponentEnum.MentionableSelect && type !== ComponentEnum.ChannelSelect)
8761
8989
  throw new TypeError("Invalid select component type.");
8762
- this.#data = { type };
8763
- }
8764
- setCustomId(value) {
8765
- validateText(value, 100, "Component custom ID");
8766
- this.#data.custom_id = value;
8767
- return this;
8768
- }
8769
- setPlaceholder(value) {
8770
- validateText(value, 150, "Component placeholder");
8771
- this.#data.placeholder = value;
8772
- return this;
8773
- }
8774
- setMinValues(value) {
8775
- validateCount(value, "min_values", 0);
8776
- this.#data.min_values = value;
8777
- return this;
8778
- }
8779
- setMaxValues(value) {
8780
- validateCount(value, "max_values", 1);
8781
- this.#data.max_values = value;
8782
- return this;
8783
- }
8784
- setRequired(value = true) {
8785
- this.#data.required = value;
8786
- return this;
8787
- }
8788
- setDisabled(value = true) {
8789
- this.#data.disabled = value;
8790
- return this;
8990
+ const data = { type };
8991
+ super(data);
8992
+ this.#data = data;
8791
8993
  }
8792
8994
  setDefaultValues(...values) {
8793
8995
  this.#data.default_values = values.map((value) => ({ ...value }));
@@ -9245,16 +9447,7 @@ class CreateSlashCommand {
9245
9447
  return structuredClone(this.#data);
9246
9448
  }
9247
9449
  addOption(option) {
9248
- const options = this.#data.options ?? [];
9249
- if (options.length >= 25)
9250
- throw new RangeError("An application command cannot contain more than 25 options.");
9251
- const payload = option.toJSON();
9252
- if (options.some((existing) => existing.name === payload.name))
9253
- throw new RangeError(`Duplicate option name: ${String(payload.name)}.`);
9254
- if (payload.required === true && options.some((existing) => existing.required !== true))
9255
- throw new RangeError("Required application command options must be placed before optional options.");
9256
- options.push(payload);
9257
- this.#data.options = options;
9450
+ this.#data.options = appendOption(this.#data.options, option.toJSON(), "application command");
9258
9451
  return this;
9259
9452
  }
9260
9453
  }
@@ -9292,21 +9485,9 @@ class CreateStringOption extends CreateCommandOption {
9292
9485
  super(ApplicationCommandOptionEnum2.String);
9293
9486
  }
9294
9487
  addChoices(...choices) {
9295
- const current = this.data.choices ?? [];
9296
- if (!choices.length)
9297
- throw new TypeError("At least one choice is required.");
9298
- if (this.data.autocomplete === true)
9299
- throw new RangeError("Autocomplete options cannot define choices.");
9300
- if (current.length + choices.length > 25)
9301
- throw new RangeError("An option cannot contain more than 25 choices.");
9302
- for (const choice of choices) {
9303
- validateText2(choice.name, "Choice name", 100);
9488
+ for (const choice of choices)
9304
9489
  validateText2(choice.value, "Choice value", 100);
9305
- }
9306
- this.data.choices = [
9307
- ...current,
9308
- ...choices.map((choice) => ({ ...choice }))
9309
- ];
9490
+ appendChoices(this.data, choices);
9310
9491
  return this;
9311
9492
  }
9312
9493
  setMinLength(value) {
@@ -9323,18 +9504,21 @@ class CreateStringOption extends CreateCommandOption {
9323
9504
  }
9324
9505
  }
9325
9506
 
9326
- class CreateIntegerOption extends CreateCommandOption {
9327
- constructor() {
9328
- super(ApplicationCommandOptionEnum2.Integer);
9507
+ class CreateNumericOption extends CreateCommandOption {
9508
+ #integer;
9509
+ constructor(type, integer) {
9510
+ super(type);
9511
+ this.#integer = integer;
9329
9512
  }
9330
9513
  setMinValue(value) {
9331
- validateNumberRange(value, -9007199254740991, 9007199254740991, "min_value", true);
9514
+ validateNumberRange(value, -MAX_SAFE, MAX_SAFE, "min_value", this.#integer);
9332
9515
  this.data.min_value = value;
9333
9516
  return this;
9334
9517
  }
9335
9518
  setMaxValue(value) {
9336
- validateNumberRange(value, -9007199254740991, 9007199254740991, "max_value", true);
9337
- if (this.data.min_value !== undefined && this.data.min_value > value)
9519
+ validateNumberRange(value, -MAX_SAFE, MAX_SAFE, "max_value", this.#integer);
9520
+ const min = this.data.min_value;
9521
+ if (min !== undefined && min > value)
9338
9522
  throw new RangeError("min_value cannot exceed max_value.");
9339
9523
  this.data.max_value = value;
9340
9524
  return this;
@@ -9346,50 +9530,20 @@ class CreateIntegerOption extends CreateCommandOption {
9346
9530
  return this;
9347
9531
  }
9348
9532
  addChoices(...choices) {
9349
- const current = this.data.choices ?? [];
9350
- if (!choices.length)
9351
- throw new TypeError("At least one choice is required.");
9352
- if (this.data.autocomplete === true)
9353
- throw new RangeError("Autocomplete options cannot define choices.");
9354
- if (current.length + choices.length > 25)
9355
- throw new RangeError("An option cannot contain more than 25 choices.");
9356
- this.data.choices = [...current, ...choices];
9533
+ appendChoices(this.data, choices);
9357
9534
  return this;
9358
9535
  }
9359
9536
  }
9360
9537
 
9361
- class CreateNumberOption extends CreateCommandOption {
9538
+ class CreateIntegerOption extends CreateNumericOption {
9362
9539
  constructor() {
9363
- super(ApplicationCommandOptionEnum2.Number);
9540
+ super(ApplicationCommandOptionEnum2.Integer, true);
9364
9541
  }
9365
- setMinValue(value) {
9366
- validateNumberRange(value, -9007199254740991, 9007199254740991, "min_value", false);
9367
- this.data.min_value = value;
9368
- return this;
9369
- }
9370
- setMaxValue(value) {
9371
- validateNumberRange(value, -9007199254740991, 9007199254740991, "max_value", false);
9372
- if (this.data.min_value !== undefined && this.data.min_value > value)
9373
- throw new RangeError("min_value cannot exceed max_value.");
9374
- this.data.max_value = value;
9375
- return this;
9376
- }
9377
- setAutocomplete(enabled = true) {
9378
- if (enabled && Array.isArray(this.data.choices) && this.data.choices.length)
9379
- throw new RangeError("Autocomplete options cannot define choices.");
9380
- this.data.autocomplete = enabled;
9381
- return this;
9382
- }
9383
- addChoices(...choices) {
9384
- const current = this.data.choices ?? [];
9385
- if (!choices.length)
9386
- throw new TypeError("At least one choice is required.");
9387
- if (this.data.autocomplete === true)
9388
- throw new RangeError("Autocomplete options cannot define choices.");
9389
- if (current.length + choices.length > 25)
9390
- throw new RangeError("An option cannot contain more than 25 choices.");
9391
- this.data.choices = [...current, ...choices];
9392
- return this;
9542
+ }
9543
+
9544
+ class CreateNumberOption extends CreateNumericOption {
9545
+ constructor() {
9546
+ super(ApplicationCommandOptionEnum2.Number, false);
9393
9547
  }
9394
9548
  }
9395
9549
 
@@ -9468,17 +9622,9 @@ class CreateSubcommand extends CreateCommandOption {
9468
9622
  }
9469
9623
  addChildOption(option) {
9470
9624
  const options = this.data.options ?? [];
9471
- if (options.length >= 25)
9472
- throw new RangeError("A subcommand cannot contain more than 25 options.");
9473
- const payload = option.toJSON();
9474
- if (options.some((existing) => existing.name === payload.name))
9475
- throw new RangeError(`Duplicate option name: ${String(payload.name)}.`);
9476
- if (payload.required === true && options.some((existing) => existing.required !== true))
9477
- throw new RangeError("Required subcommand options must be placed before optional options.");
9478
9625
  if (options.some((existing) => existing.type === ApplicationCommandOptionEnum2.Subcommand))
9479
9626
  throw new RangeError("Subcommands cannot contain nested subcommands.");
9480
- options.push(payload);
9481
- this.data.options = options;
9627
+ this.data.options = appendOption(options, option.toJSON(), "subcommand");
9482
9628
  return this;
9483
9629
  }
9484
9630
  }
@@ -9501,6 +9647,29 @@ class CreateSubcommandGroup extends CreateCommandOption {
9501
9647
  return this;
9502
9648
  }
9503
9649
  }
9650
+ var MAX_SAFE = Number.MAX_SAFE_INTEGER;
9651
+ function appendOption(options, payload, parent) {
9652
+ const list = options ?? [];
9653
+ if (list.length >= 25)
9654
+ throw new RangeError(`${parent === "subcommand" ? "A subcommand" : "An application command"} cannot contain more than 25 options.`);
9655
+ if (list.some((existing) => existing.name === payload.name))
9656
+ throw new RangeError(`Duplicate option name: ${String(payload.name)}.`);
9657
+ if (payload.required === true && list.some((existing) => existing.required !== true))
9658
+ throw new RangeError(`Required ${parent} options must be placed before optional options.`);
9659
+ return [...list, payload];
9660
+ }
9661
+ function appendChoices(data, choices) {
9662
+ const current = data.choices ?? [];
9663
+ if (!choices.length)
9664
+ throw new TypeError("At least one choice is required.");
9665
+ if (data.autocomplete === true)
9666
+ throw new RangeError("Autocomplete options cannot define choices.");
9667
+ if (current.length + choices.length > 25)
9668
+ throw new RangeError("An option cannot contain more than 25 choices.");
9669
+ for (const choice of choices)
9670
+ validateText2(choice.name, "Choice name", 100);
9671
+ data.choices = [...current, ...choices.map((choice) => ({ ...choice }))];
9672
+ }
9504
9673
  function validateName(value, field) {
9505
9674
  if (!/^[\p{L}\p{N}_-]{1,32}$/u.test(value) || value !== value.toLowerCase())
9506
9675
  throw new RangeError(`${field} must contain 1-32 lowercase letters, numbers, underscores, or hyphens.`);
@@ -9589,13 +9758,14 @@ var SubcommandGroupBuilder = CreateSubcommandGroup;
9589
9758
  var UserCommandBuilder = CreateUserCommand;
9590
9759
  var UserOptionBuilder = CreateUserOption;
9591
9760
  // packages/builders/src/attachment.ts
9592
- import { readFile } from "fs/promises";
9593
- import { basename } from "path";
9761
+ import { readFile, realpath } from "fs/promises";
9762
+ import { basename, isAbsolute, relative, resolve } from "path";
9594
9763
 
9595
9764
  class CreateAttachment {
9596
9765
  name;
9597
9766
  description;
9598
9767
  file;
9768
+ root;
9599
9769
  constructor(file, data) {
9600
9770
  this.file = file;
9601
9771
  if (typeof data === "string") {
@@ -9603,6 +9773,7 @@ class CreateAttachment {
9603
9773
  } else {
9604
9774
  this.name = data?.name ?? (typeof file === "string" ? basename(file) : "file.bin");
9605
9775
  this.description = data?.description;
9776
+ this.root = data?.root;
9606
9777
  }
9607
9778
  }
9608
9779
  setName(name) {
@@ -9619,7 +9790,8 @@ class CreateAttachment {
9619
9790
  }
9620
9791
  async toBuffer() {
9621
9792
  if (typeof this.file === "string") {
9622
- const buffer = await readFile(this.file);
9793
+ const path = this.root === undefined ? this.file : await insideRoot(this.root, this.file);
9794
+ const buffer = await readFile(path);
9623
9795
  return new Uint8Array(buffer);
9624
9796
  }
9625
9797
  if (this.file instanceof Uint8Array)
@@ -9637,6 +9809,16 @@ class CreateAttachment {
9637
9809
  }
9638
9810
  }
9639
9811
  var AttachmentBuilder = CreateAttachment;
9812
+ async function insideRoot(root, file) {
9813
+ const base = await realpath(root);
9814
+ const target = await realpath(resolve(base, file)).catch(() => {
9815
+ throw new Error("Attachment file was not found inside its root.");
9816
+ });
9817
+ const rel = relative(base, target);
9818
+ if (rel === "" || rel.startsWith("..") || isAbsolute(rel))
9819
+ throw new Error("Attachment file is outside its root folder.");
9820
+ return target;
9821
+ }
9640
9822
  export {
9641
9823
  ActionRowBuilder,
9642
9824
  ActivityEnum,
@@ -9910,4 +10092,4 @@ export {
9910
10092
  userMention
9911
10093
  };
9912
10094
 
9913
- //# debugId=97695754EB32311964756E2164756E21
10095
+ //# debugId=4ECD86428171907F64756E2164756E21