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
@@ -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 {
@@ -813,67 +761,37 @@ var InteractionResponseEnum = {
813
761
  Modal: 9
814
762
  };
815
763
  // packages/collection/src/index.ts
816
- class RecencyList {
817
- #nodes = new Map;
818
- #oldest;
819
- #newest;
820
- get size() {
821
- return this.#nodes.size;
822
- }
823
- oldest() {
824
- return this.#oldest?.key;
825
- }
826
- touch(key) {
827
- const node = this.#nodes.get(key);
828
- if (node)
829
- return this.#moveNewest(node);
830
- const created = { key, older: this.#newest };
831
- if (this.#newest)
832
- this.#newest.newer = created;
833
- else
834
- this.#oldest = created;
835
- this.#newest = created;
836
- this.#nodes.set(key, created);
837
- }
838
- promote(key) {
839
- const node = this.#nodes.get(key);
840
- if (node)
841
- this.#moveNewest(node);
842
- }
843
- delete(key) {
844
- const node = this.#nodes.get(key);
845
- if (!node)
846
- return false;
847
- this.#unlink(node);
848
- this.#nodes.delete(key);
849
- return true;
850
- }
851
- clear() {
852
- this.#nodes.clear();
853
- this.#oldest = this.#newest = undefined;
854
- }
855
- #unlink(node) {
856
- if (node.older)
857
- node.older.newer = node.newer;
858
- else
859
- this.#oldest = node.newer;
860
- if (node.newer)
861
- node.newer.older = node.older;
862
- else
863
- this.#newest = node.older;
864
- node.older = node.newer = undefined;
865
- }
866
- #moveNewest(node) {
867
- if (node === this.#newest)
868
- return;
869
- this.#unlink(node);
870
- node.older = this.#newest;
871
- if (this.#newest)
872
- this.#newest.newer = node;
873
- else
874
- this.#oldest = node;
875
- this.#newest = node;
876
- }
764
+ function newPolicy(options = {}) {
765
+ return {
766
+ ttl: options.ttl,
767
+ maxSize: options.maxSize,
768
+ slide: options.slide ?? true,
769
+ onEvict: options.onEvict,
770
+ expired: 0,
771
+ evicted: 0,
772
+ entries: new Map,
773
+ oldest: undefined,
774
+ newest: undefined,
775
+ lruSize: 0,
776
+ heap: [],
777
+ armedFor: Infinity
778
+ };
779
+ }
780
+ function peekOf(collection, key) {
781
+ return collection instanceof Map ? Map.prototype.get.call(collection, key) : collection.get(key);
782
+ }
783
+ var mapGet = Map.prototype.get;
784
+ var mapHas = Map.prototype.has;
785
+ function sample(items, amount) {
786
+ if (!Number.isInteger(amount) || amount < 0)
787
+ throw new RangeError("amount must be a non-negative integer.");
788
+ const count = Math.min(amount, items.length);
789
+ for (let i = 0;i < count; i++) {
790
+ const j = i + Math.floor(Math.random() * (items.length - i));
791
+ [items[i], items[j]] = [items[j], items[i]];
792
+ }
793
+ items.length = count;
794
+ return items;
877
795
  }
878
796
  function assertTTL(ttl) {
879
797
  if (ttl !== undefined && (!Number.isFinite(ttl) || ttl <= 0))
@@ -881,81 +799,90 @@ function assertTTL(ttl) {
881
799
  }
882
800
 
883
801
  class Collection extends Map {
884
- #ttl;
885
- #maxSize;
886
- #onEvict;
887
- #expiry = new Map;
888
- #lru = new RecencyList;
889
- #stats = {
890
- hits: 0,
891
- misses: 0,
892
- expired: 0,
893
- evicted: 0
894
- };
895
- #heap = [];
896
- #timer;
897
- #armedFor = Infinity;
802
+ #policy;
803
+ #hits = 0;
804
+ #misses = 0;
898
805
  constructor(entries, options = {}) {
899
806
  super();
900
807
  assertTTL(options.ttl);
901
808
  if (options.maxSize !== undefined && (!Number.isInteger(options.maxSize) || options.maxSize <= 0))
902
809
  throw new RangeError("maxSize must be a positive integer.");
903
- this.#ttl = options.ttl;
904
- this.#maxSize = options.maxSize;
905
- this.#onEvict = options.onEvict;
810
+ if (options.ttl !== undefined || options.maxSize !== undefined || options.slide !== undefined || options.onEvict !== undefined)
811
+ this.#policy = newPolicy(options);
906
812
  if (entries)
907
813
  for (const [key, value] of entries)
908
814
  this.set(key, value);
909
815
  }
910
816
  set(key, value, ttl) {
817
+ if (ttl === undefined && this.#policy === undefined)
818
+ return super.set(key, value);
911
819
  assertTTL(ttl);
912
- const window = ttl ?? this.#ttl;
913
- if (this.#maxSize !== undefined) {
914
- this.#lru.touch(key);
915
- }
916
- super.set(key, value);
820
+ const window = ttl ?? this.#policy?.ttl;
917
821
  if (window !== undefined)
918
- this.#schedule(key, window);
919
- else if (this.#expiry.size > 0)
920
- this.#expiry.delete(key);
822
+ this.#policy ??= newPolicy();
823
+ if (!this.#policy)
824
+ return super.set(key, value);
825
+ const before = super.size;
826
+ super.set(key, value);
827
+ this.#track(key, value, window, super.size !== before);
921
828
  this.#enforceCap();
922
829
  return this;
923
830
  }
924
831
  setWithoutTTL(key, value) {
925
- if (this.#expiry.size > 0)
926
- this.#expiry.delete(key);
927
- if (this.#lru.size > 0)
928
- this.#lru.delete(key);
832
+ if (this.#policy)
833
+ this.#forget(key);
929
834
  super.set(key, value);
930
835
  return this;
931
836
  }
932
837
  get(key) {
933
- if (this.#expireIfDue(key)) {
934
- this.#stats.misses++;
838
+ const policy = this.#policy;
839
+ const entry = policy?.entries.get(key);
840
+ if (entry === undefined) {
841
+ const value = mapGet.call(this, key);
842
+ if (value !== undefined || mapHas.call(this, key)) {
843
+ this.#hits++;
844
+ return value;
845
+ }
846
+ this.#misses++;
935
847
  return;
936
848
  }
937
- const value = super.get(key);
938
- if (value === undefined && !super.has(key)) {
939
- this.#stats.misses++;
849
+ const timed = entry.window !== 0;
850
+ const now = timed ? Date.now() : 0;
851
+ if (timed && entry.deadline <= now) {
852
+ this.#expire(entry);
853
+ this.#misses++;
940
854
  return;
941
855
  }
942
- this.#stats.hits++;
943
- const expiry = this.#expiry.get(key);
944
- if (expiry)
945
- expiry.deadline = Date.now() + expiry.window;
946
- this.#lru.promote(key);
947
- return value;
856
+ this.#hits++;
857
+ if (timed && policy.slide)
858
+ entry.deadline = now + entry.window;
859
+ if (entry.inLru)
860
+ this.#promote(policy, entry);
861
+ return entry.value;
862
+ }
863
+ ensure(key, factory, ttl) {
864
+ const existing = this.get(key);
865
+ if (existing !== undefined || super.has(key))
866
+ return existing;
867
+ const created = factory(key, this);
868
+ this.set(key, created, ttl);
869
+ return created;
948
870
  }
949
871
  peek(key) {
950
872
  if (!this.#expireIfDue(key) && super.has(key)) {
951
- this.#stats.hits++;
873
+ this.#hits++;
952
874
  return super.get(key);
953
875
  }
954
- this.#stats.misses++;
876
+ this.#misses++;
955
877
  return;
956
878
  }
957
879
  get stats() {
958
- return { ...this.#stats };
880
+ return {
881
+ hits: this.#hits,
882
+ misses: this.#misses,
883
+ expired: this.#policy?.expired ?? 0,
884
+ evicted: this.#policy?.evicted ?? 0
885
+ };
959
886
  }
960
887
  has(key) {
961
888
  return !this.#expireIfDue(key) && super.has(key);
@@ -963,19 +890,23 @@ class Collection extends Map {
963
890
  delete(key) {
964
891
  if (this.#expireIfDue(key))
965
892
  return false;
966
- this.#expiry.delete(key);
967
- this.#lru.delete(key);
893
+ if (this.#policy)
894
+ this.#forget(key);
968
895
  return super.delete(key);
969
896
  }
970
897
  clear() {
971
898
  super.clear();
972
- this.#expiry.clear();
973
- this.#lru.clear();
974
- this.#heap.length = 0;
975
- if (this.#timer)
976
- clearTimeout(this.#timer);
977
- this.#timer = undefined;
978
- this.#armedFor = Infinity;
899
+ const policy = this.#policy;
900
+ if (!policy)
901
+ return;
902
+ policy.entries.clear();
903
+ policy.oldest = policy.newest = undefined;
904
+ policy.lruSize = 0;
905
+ policy.heap.length = 0;
906
+ if (policy.timer)
907
+ clearTimeout(policy.timer);
908
+ policy.timer = undefined;
909
+ policy.armedFor = Infinity;
979
910
  }
980
911
  get size() {
981
912
  this.purge();
@@ -1003,11 +934,11 @@ class Collection extends Map {
1003
934
  ttlRemaining(key) {
1004
935
  if (this.#expireIfDue(key))
1005
936
  return;
1006
- const expiry = this.#expiry.get(key);
1007
- return expiry && Math.max(0, expiry.deadline - Date.now());
937
+ const entry = this.#policy?.entries.get(key);
938
+ return entry && entry.window !== 0 ? Math.max(0, entry.deadline - Date.now()) : undefined;
1008
939
  }
1009
940
  purge() {
1010
- if (this.#expiry.size === 0)
941
+ if (!this.#policy || this.#policy.heap.length === 0)
1011
942
  return 0;
1012
943
  const now = Date.now();
1013
944
  let removed = 0;
@@ -1018,133 +949,255 @@ class Collection extends Map {
1018
949
  this.#remove(due.key);
1019
950
  removed++;
1020
951
  }
1021
- this.#stats.expired += removed;
952
+ this.#policy.expired += removed;
1022
953
  this.#rearm();
1023
954
  for (const [key, value] of dropped)
1024
955
  this.#notify(key, value, "expired");
1025
956
  return removed;
1026
957
  }
1027
958
  #expireIfDue(key) {
1028
- const expiry = this.#expiry.get(key);
1029
- if (!expiry || expiry.deadline > Date.now())
959
+ const entry = this.#policy?.entries.get(key);
960
+ if (!entry || entry.window === 0 || entry.deadline > Date.now())
1030
961
  return false;
1031
- const value = super.get(key);
1032
- this.#remove(key);
1033
- this.#stats.expired++;
1034
- this.#notify(key, value, "expired");
962
+ this.#expire(entry);
1035
963
  return true;
1036
964
  }
965
+ #expire(entry) {
966
+ const value = super.get(entry.key);
967
+ this.#remove(entry.key);
968
+ this.#policy.expired++;
969
+ this.#notify(entry.key, value, "expired");
970
+ }
1037
971
  #remove(key) {
1038
- this.#expiry.delete(key);
1039
- this.#lru.delete(key);
972
+ this.#forget(key);
1040
973
  super.delete(key);
1041
974
  }
975
+ #forget(key) {
976
+ const policy = this.#policy;
977
+ const entry = policy.entries.get(key);
978
+ if (!entry)
979
+ return;
980
+ if (entry.inLru)
981
+ this.#unlink(policy, entry);
982
+ policy.entries.delete(key);
983
+ }
984
+ #track(key, value, window, isNew) {
985
+ const policy = this.#policy;
986
+ const lru = policy.maxSize !== undefined;
987
+ let entry = isNew ? undefined : policy.entries.get(key);
988
+ if (entry)
989
+ entry.value = value;
990
+ if (window === undefined) {
991
+ if (entry && entry.window !== 0) {
992
+ if (lru)
993
+ entry = this.#replace(policy, entry, 0, 0);
994
+ else {
995
+ this.#forget(key);
996
+ return;
997
+ }
998
+ }
999
+ if (!entry && lru) {
1000
+ entry = this.#create(key, value, 0, 0);
1001
+ policy.entries.set(key, entry);
1002
+ }
1003
+ if (entry)
1004
+ this.#promote(policy, entry);
1005
+ return;
1006
+ }
1007
+ const deadline = Date.now() + window;
1008
+ if (entry && entry.window !== 0) {
1009
+ entry.deadline = deadline;
1010
+ entry.window = window;
1011
+ if (deadline < entry.filed)
1012
+ entry = this.#replace(policy, entry, window, deadline);
1013
+ else {
1014
+ if (entry.inLru)
1015
+ this.#promote(policy, entry);
1016
+ return;
1017
+ }
1018
+ } else if (entry) {
1019
+ entry.window = window;
1020
+ entry.deadline = entry.filed = deadline;
1021
+ } else {
1022
+ entry = this.#create(key, value, window, deadline);
1023
+ policy.entries.set(key, entry);
1024
+ }
1025
+ if (lru)
1026
+ this.#promote(policy, entry);
1027
+ this.#heapPush(entry);
1028
+ if (policy.heap.length > 2 * policy.entries.size + 8)
1029
+ this.#compact();
1030
+ if (policy.timer === undefined || deadline < policy.armedFor)
1031
+ this.#rearm();
1032
+ }
1033
+ #create(key, value, window, deadline) {
1034
+ return {
1035
+ key,
1036
+ value,
1037
+ older: undefined,
1038
+ newer: undefined,
1039
+ inLru: false,
1040
+ window,
1041
+ deadline,
1042
+ filed: deadline
1043
+ };
1044
+ }
1045
+ #replace(policy, old, window, deadline) {
1046
+ const entry = {
1047
+ ...old,
1048
+ window,
1049
+ deadline,
1050
+ filed: deadline
1051
+ };
1052
+ if (old.inLru) {
1053
+ if (old.older)
1054
+ old.older.newer = entry;
1055
+ else
1056
+ policy.oldest = entry;
1057
+ if (old.newer)
1058
+ old.newer.older = entry;
1059
+ else
1060
+ policy.newest = entry;
1061
+ }
1062
+ policy.entries.set(old.key, entry);
1063
+ return entry;
1064
+ }
1065
+ #promote(policy, entry) {
1066
+ if (entry === policy.newest)
1067
+ return;
1068
+ if (entry.inLru)
1069
+ this.#unlink(policy, entry, true);
1070
+ else {
1071
+ entry.inLru = true;
1072
+ policy.lruSize++;
1073
+ }
1074
+ entry.older = policy.newest;
1075
+ entry.newer = undefined;
1076
+ if (policy.newest)
1077
+ policy.newest.newer = entry;
1078
+ else
1079
+ policy.oldest = entry;
1080
+ policy.newest = entry;
1081
+ }
1082
+ #unlink(policy, entry, keepCount = false) {
1083
+ if (entry.older)
1084
+ entry.older.newer = entry.newer;
1085
+ else
1086
+ policy.oldest = entry.newer;
1087
+ if (entry.newer)
1088
+ entry.newer.older = entry.older;
1089
+ else
1090
+ policy.newest = entry.older;
1091
+ entry.older = entry.newer = undefined;
1092
+ if (!keepCount) {
1093
+ entry.inLru = false;
1094
+ policy.lruSize--;
1095
+ }
1096
+ }
1097
+ #derived() {
1098
+ const Species = this.constructor[Symbol.species] ?? Collection;
1099
+ return new Species;
1100
+ }
1042
1101
  #notify(key, value, reason) {
1043
- if (!this.#onEvict)
1102
+ const onEvict = this.#policy?.onEvict;
1103
+ if (!onEvict)
1044
1104
  return;
1045
1105
  try {
1046
- this.#onEvict(key, value, reason);
1106
+ onEvict(key, value, reason);
1047
1107
  } catch {}
1048
1108
  }
1049
1109
  #enforceCap() {
1050
- if (this.#maxSize === undefined)
1110
+ const policy = this.#policy;
1111
+ const max = policy.maxSize;
1112
+ if (max === undefined)
1051
1113
  return;
1052
- while (this.#lru.size > this.#maxSize) {
1053
- const oldest = this.#lru.oldest();
1054
- const value = super.get(oldest);
1055
- this.#remove(oldest);
1056
- this.#stats.evicted++;
1057
- this.#notify(oldest, value, "evicted");
1114
+ if (policy.lruSize > max && policy.heap.length > 0 && policy.heap[0].filed <= Date.now())
1115
+ this.purge();
1116
+ while (policy.lruSize > max) {
1117
+ const oldest = policy.oldest;
1118
+ const value = policy.onEvict ? super.get(oldest.key) : undefined;
1119
+ this.#unlink(policy, oldest);
1120
+ policy.entries.delete(oldest.key);
1121
+ super.delete(oldest.key);
1122
+ policy.evicted++;
1123
+ this.#notify(oldest.key, value, "evicted");
1058
1124
  }
1059
1125
  }
1060
- #schedule(key, window) {
1061
- const deadline = Date.now() + window;
1062
- const expiry = this.#expiry.get(key);
1063
- if (expiry) {
1064
- expiry.deadline = deadline;
1065
- expiry.window = window;
1066
- if (deadline >= expiry.filed)
1067
- return;
1068
- expiry.filed = deadline;
1069
- } else
1070
- this.#expiry.set(key, { deadline, window, filed: deadline });
1071
- this.#heapPush({ key, deadline });
1072
- if (this.#heap.length > 2 * this.#expiry.size + 8)
1073
- this.#compact();
1074
- this.#rearm();
1075
- }
1076
1126
  #nextDeadline() {
1127
+ const policy = this.#policy;
1077
1128
  for (;; ) {
1078
- const top = this.#heap[0];
1129
+ const top = policy.heap[0];
1079
1130
  if (top === undefined)
1080
1131
  return Infinity;
1081
- const expiry = this.#expiry.get(top.key);
1082
- if (!expiry || expiry.filed !== top.deadline) {
1132
+ if (policy.entries.get(top.key) !== top) {
1083
1133
  this.#heapPop();
1084
1134
  continue;
1085
1135
  }
1086
- if (expiry.deadline === top.deadline)
1087
- return top.deadline;
1136
+ if (top.deadline === top.filed)
1137
+ return top.filed;
1088
1138
  this.#heapPop();
1089
- expiry.filed = expiry.deadline;
1090
- this.#heapPush({ key: top.key, deadline: expiry.deadline });
1139
+ top.filed = top.deadline;
1140
+ this.#heapPush(top);
1091
1141
  }
1092
1142
  }
1093
1143
  #compact() {
1094
- const live = this.#heap.filter((record) => this.#expiry.get(record.key)?.filed === record.deadline);
1095
- this.#heap.length = 0;
1096
- for (const record of live)
1097
- this.#heapPush(record);
1144
+ const policy = this.#policy;
1145
+ const live = policy.heap.filter((entry) => policy.entries.get(entry.key) === entry);
1146
+ policy.heap.length = 0;
1147
+ for (const entry of live)
1148
+ this.#heapPush(entry);
1098
1149
  }
1099
1150
  #rearm() {
1151
+ const p = this.#policy;
1100
1152
  const deadline = this.#nextDeadline();
1101
- if (this.#timer !== undefined && deadline >= this.#armedFor)
1153
+ if (p.timer !== undefined && deadline >= p.armedFor)
1102
1154
  return;
1103
- if (this.#timer)
1104
- clearTimeout(this.#timer);
1105
- this.#timer = undefined;
1106
- this.#armedFor = deadline;
1155
+ if (p.timer)
1156
+ clearTimeout(p.timer);
1157
+ p.timer = undefined;
1158
+ p.armedFor = deadline;
1107
1159
  if (deadline === Infinity)
1108
1160
  return;
1109
- this.#timer = setTimeout(() => {
1110
- this.#timer = undefined;
1111
- this.#armedFor = Infinity;
1161
+ p.timer = setTimeout(() => {
1162
+ p.timer = undefined;
1163
+ p.armedFor = Infinity;
1112
1164
  this.purge();
1113
1165
  }, Math.max(0, deadline - Date.now()));
1114
- this.#timer.unref?.();
1166
+ p.timer.unref?.();
1115
1167
  }
1116
- #heapPush(record) {
1117
- const heap = this.#heap;
1118
- heap.push(record);
1119
- let i = heap.length - 1;
1168
+ #heapPush(entry) {
1169
+ const heap = this.#policy.heap;
1170
+ let i = heap.length;
1171
+ heap.push(entry);
1120
1172
  while (i > 0) {
1121
1173
  const parent = i - 1 >> 1;
1122
- if (heap[parent].deadline <= heap[i].deadline)
1174
+ const above = heap[parent];
1175
+ if (above.filed <= entry.filed)
1123
1176
  break;
1124
- [heap[parent], heap[i]] = [heap[i], heap[parent]];
1177
+ heap[i] = above;
1125
1178
  i = parent;
1126
1179
  }
1180
+ heap[i] = entry;
1127
1181
  }
1128
1182
  #heapPop() {
1129
- const heap = this.#heap;
1183
+ const heap = this.#policy.heap;
1130
1184
  const top = heap[0];
1131
1185
  const last = heap.pop();
1132
1186
  if (top === undefined || heap.length === 0)
1133
1187
  return top;
1134
- heap[0] = last;
1135
- for (let i = 0;; ) {
1136
- const left = 2 * i + 1;
1137
- const right = left + 1;
1138
- let smallest = i;
1139
- if (left < heap.length && heap[left].deadline < heap[smallest].deadline)
1140
- smallest = left;
1141
- if (right < heap.length && heap[right].deadline < heap[smallest].deadline)
1142
- smallest = right;
1143
- if (smallest === i)
1188
+ let i = 0;
1189
+ for (;; ) {
1190
+ let child = 2 * i + 1;
1191
+ if (child >= heap.length)
1192
+ break;
1193
+ if (child + 1 < heap.length && heap[child + 1].filed < heap[child].filed)
1194
+ child++;
1195
+ if (heap[child].filed >= last.filed)
1144
1196
  break;
1145
- [heap[smallest], heap[i]] = [heap[i], heap[smallest]];
1146
- i = smallest;
1197
+ heap[i] = heap[child];
1198
+ i = child;
1147
1199
  }
1200
+ heap[i] = last;
1148
1201
  return top;
1149
1202
  }
1150
1203
  first() {
@@ -1176,8 +1229,26 @@ class Collection extends Map {
1176
1229
  }
1177
1230
  return;
1178
1231
  }
1232
+ findLast(predicate) {
1233
+ const entries = [...this];
1234
+ for (let i = entries.length - 1;i >= 0; i--) {
1235
+ const [key, value] = entries[i];
1236
+ if (predicate(value, key, this))
1237
+ return value;
1238
+ }
1239
+ return;
1240
+ }
1241
+ findLastKey(predicate) {
1242
+ const entries = [...this];
1243
+ for (let i = entries.length - 1;i >= 0; i--) {
1244
+ const [key, value] = entries[i];
1245
+ if (predicate(value, key, this))
1246
+ return key;
1247
+ }
1248
+ return;
1249
+ }
1179
1250
  filter(predicate) {
1180
- const result = new Collection;
1251
+ const result = this.#derived();
1181
1252
  for (const [key, value] of this) {
1182
1253
  if (predicate(value, key, this))
1183
1254
  result.set(key, value);
@@ -1221,7 +1292,7 @@ class Collection extends Map {
1221
1292
  return [...this.entries()];
1222
1293
  }
1223
1294
  clone() {
1224
- const copy = new Collection;
1295
+ const copy = this.#derived();
1225
1296
  for (const [key, value] of this)
1226
1297
  copy.set(key, value);
1227
1298
  return copy;
@@ -1276,7 +1347,7 @@ class Collection extends Map {
1276
1347
  return result;
1277
1348
  }
1278
1349
  intersection(other) {
1279
- const result = new Collection;
1350
+ const result = this.#derived();
1280
1351
  for (const [key, value] of this) {
1281
1352
  if (other.has(key))
1282
1353
  result.set(key, value);
@@ -1284,7 +1355,7 @@ class Collection extends Map {
1284
1355
  return result;
1285
1356
  }
1286
1357
  difference(other) {
1287
- const result = new Collection;
1358
+ const result = this.#derived();
1288
1359
  for (const [key, value] of this) {
1289
1360
  if (!other.has(key))
1290
1361
  result.set(key, value);
@@ -1292,8 +1363,8 @@ class Collection extends Map {
1292
1363
  return result;
1293
1364
  }
1294
1365
  partition(predicate) {
1295
- const pass = new Collection;
1296
- const fail = new Collection;
1366
+ const pass = this.#derived();
1367
+ const fail = this.#derived();
1297
1368
  for (const [key, value] of this) {
1298
1369
  if (predicate(value, key, this))
1299
1370
  pass.set(key, value);
@@ -1302,6 +1373,81 @@ class Collection extends Map {
1302
1373
  }
1303
1374
  return [pass, fail];
1304
1375
  }
1376
+ symmetricDifference(other) {
1377
+ const result = this.#derived();
1378
+ for (const [key, value] of this)
1379
+ if (!other.has(key))
1380
+ result.set(key, value);
1381
+ for (const [key, value] of other)
1382
+ if (!this.has(key))
1383
+ result.set(key, value);
1384
+ return result;
1385
+ }
1386
+ concat(...collections) {
1387
+ const result = this.clone();
1388
+ for (const collection of collections)
1389
+ for (const [key, value] of collection)
1390
+ result.set(key, value);
1391
+ return result;
1392
+ }
1393
+ merge(other, whenInSelf, whenInOther, whenInBoth) {
1394
+ const result = this.#derived();
1395
+ const decide = (key, kept) => {
1396
+ if (kept.keep)
1397
+ result.set(key, kept.value);
1398
+ };
1399
+ for (const [key, value] of this) {
1400
+ decide(key, other.has(key) ? whenInBoth(value, peekOf(other, key), key) : whenInSelf(value, key));
1401
+ }
1402
+ for (const [key, value] of other)
1403
+ if (!this.has(key))
1404
+ decide(key, whenInOther(value, key));
1405
+ return result;
1406
+ }
1407
+ equals(other) {
1408
+ if (!other)
1409
+ return false;
1410
+ if (other === this)
1411
+ return true;
1412
+ if (this.size !== other.size)
1413
+ return false;
1414
+ for (const [key, value] of this) {
1415
+ if (!other.has(key))
1416
+ return false;
1417
+ if (value !== peekOf(other, key))
1418
+ return false;
1419
+ }
1420
+ return true;
1421
+ }
1422
+ mapValues(transform) {
1423
+ const result = this.#derived();
1424
+ for (const [key, value] of this)
1425
+ result.set(key, transform(value, key, this));
1426
+ return result;
1427
+ }
1428
+ toReversed() {
1429
+ const result = this.#derived();
1430
+ const entries = [...this];
1431
+ for (let i = entries.length - 1;i >= 0; i--)
1432
+ result.set(entries[i][0], entries[i][1]);
1433
+ return result;
1434
+ }
1435
+ toSorted(comparator) {
1436
+ return this.sorted(comparator);
1437
+ }
1438
+ static groupBy(items, keySelector) {
1439
+ const groups = new Collection;
1440
+ let index = 0;
1441
+ for (const item of items)
1442
+ groups.ensure(keySelector(item, index++), () => []).push(item);
1443
+ return groups;
1444
+ }
1445
+ static combineEntries(entries, combine) {
1446
+ const result = new Collection;
1447
+ for (const [key, value] of entries)
1448
+ result.set(key, result.has(key) ? combine(result.get(key), value, key) : value);
1449
+ return result;
1450
+ }
1305
1451
  tap(fn) {
1306
1452
  fn(this);
1307
1453
  return this;
@@ -1320,6 +1466,13 @@ class Collection extends Map {
1320
1466
  acc = fn(acc, value, key, this);
1321
1467
  return acc;
1322
1468
  }
1469
+ reduceRight(fn, initialValue) {
1470
+ const entries = [...this];
1471
+ let acc = initialValue;
1472
+ for (let i = entries.length - 1;i >= 0; i--)
1473
+ acc = fn(acc, entries[i][1], entries[i][0], this);
1474
+ return acc;
1475
+ }
1323
1476
  sorted(comparator) {
1324
1477
  const decorated = [...this.entries()].map((entry, index) => ({
1325
1478
  entry,
@@ -1330,22 +1483,34 @@ class Collection extends Map {
1330
1483
  const comparison = comparator(x.entry[1], y.entry[1], x.entry[0], y.entry[0]);
1331
1484
  return comparison !== 0 ? comparison : x.index - y.index;
1332
1485
  });
1333
- const result = new Collection;
1486
+ const result = this.#derived();
1334
1487
  for (const { entry } of decorated)
1335
1488
  result.set(entry[0], entry[1]);
1336
1489
  return result;
1337
1490
  }
1338
- random() {
1339
- const arr = [...this.values()];
1340
- if (!arr.length)
1491
+ random(amount) {
1492
+ if (amount !== undefined)
1493
+ return sample([...this.values()], amount);
1494
+ const size = this.size;
1495
+ if (size === 0)
1341
1496
  return;
1342
- return arr[Math.floor(Math.random() * arr.length)];
1497
+ let index = Math.floor(Math.random() * size);
1498
+ for (const value of this.values())
1499
+ if (index-- === 0)
1500
+ return value;
1501
+ return;
1343
1502
  }
1344
- randomKey() {
1345
- const arr = [...this.keys()];
1346
- if (!arr.length)
1503
+ randomKey(amount) {
1504
+ if (amount !== undefined)
1505
+ return sample([...this.keys()], amount);
1506
+ const size = this.size;
1507
+ if (size === 0)
1347
1508
  return;
1348
- return arr[Math.floor(Math.random() * arr.length)];
1509
+ let index = Math.floor(Math.random() * size);
1510
+ for (const key of this.keys())
1511
+ if (index-- === 0)
1512
+ return key;
1513
+ return;
1349
1514
  }
1350
1515
  at(index) {
1351
1516
  const arr = [...this.values()];
@@ -1469,7 +1634,7 @@ class ResourceManager extends Manager {
1469
1634
  // packages/rest/package.json
1470
1635
  var package_default = {
1471
1636
  name: "@lunibee/rest",
1472
- version: "0.2.3",
1637
+ version: "0.2.4",
1473
1638
  type: "module",
1474
1639
  module: "./src/index.ts",
1475
1640
  types: "./src/index.ts",
@@ -1550,7 +1715,7 @@ function kindFromStatus(status) {
1550
1715
  return "client";
1551
1716
  }
1552
1717
  function redactPath(path) {
1553
- return path.replace(/^(\/webhooks\/[^/?]+\/)[^/?]+/, "$1:token").replace(/^(\/interactions\/[^/?]+\/)[^/?]+/, "$1:token");
1718
+ return path.replace(/^(\/webhooks\/[^/?]+\/)[^/?]+/i, "$1:token").replace(/^(\/interactions\/[^/?]+\/)[^/?]+/i, "$1:token");
1554
1719
  }
1555
1720
  var HINTS = {
1556
1721
  50001: "The bot cannot see this resource: check that it is in the guild and has View Channel there.",
@@ -1609,19 +1774,23 @@ async function abortable(promise, signal, path) {
1609
1774
  }
1610
1775
 
1611
1776
  // packages/rest/src/route.ts
1777
+ import { createHash } from "crypto";
1612
1778
  function normalizeRoutePath(path) {
1613
1779
  const queryIndex = path.indexOf("?");
1614
1780
  const routePath = queryIndex === -1 ? path : path.slice(0, queryIndex);
1615
- return routePath.replace(/\/\d+(?=\/|$)/g, "/:id");
1781
+ return redactPath(routePath).replace(/\/\d+(?=\/|$)/g, "/:id");
1616
1782
  }
1617
1783
  function majorParameter(path) {
1618
- const match = /^\/(channels|guilds|webhooks)\/(\d+)(?:\/([^/?]+))?/.exec(path);
1784
+ const match = /^\/(channels|guilds|webhooks)\/(\d+)(?:\/([^/?]+))?/i.exec(path);
1619
1785
  if (!match)
1620
1786
  return "@none";
1621
- if (match[1] === "webhooks" && match[3] !== undefined)
1622
- return `${match[2]}:${match[3]}`;
1787
+ if (match[1].toLowerCase() === "webhooks" && match[3] !== undefined)
1788
+ return `${match[2]}:${tokenDigest(match[3])}`;
1623
1789
  return match[2];
1624
1790
  }
1791
+ function tokenDigest(token) {
1792
+ return createHash("sha256").update(token).digest("hex").slice(0, 16);
1793
+ }
1625
1794
  function scopeBucket(hashOrRoute, major) {
1626
1795
  return `${hashOrRoute}|${major}`;
1627
1796
  }
@@ -1863,6 +2032,9 @@ var Routes = {
1863
2032
  user: () => "/users/@me",
1864
2033
  userById: (userId) => `/users/${snowflake(userId, "User ID")}`,
1865
2034
  guild: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}`,
2035
+ currentUserGuild: (guildId) => `/users/@me/guilds/${snowflake(guildId, "Guild ID")}`,
2036
+ sticker: (stickerId) => `/stickers/${snowflake(stickerId, "Sticker ID")}`,
2037
+ messageReactionUser: (channelId, messageId, emoji, userId) => `${Routes.messageReactions(channelId, messageId, emoji)}/${snowflake(userId, "User ID")}`,
1866
2038
  guildPreview: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/preview`,
1867
2039
  guildActiveThreads: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/threads/active`,
1868
2040
  guildWebhooks: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/webhooks`,
@@ -1945,6 +2117,22 @@ function snowflake(value, field) {
1945
2117
  var LIBRARY_VERSION = package_default.version;
1946
2118
  var LIBRARY_URL = "https://github.com/Ekretos/lunibee";
1947
2119
  var USER_AGENT = `DiscordBot (${LIBRARY_URL}, ${LIBRARY_VERSION})`;
2120
+ function assertSafePath(path) {
2121
+ const end = path.search(/[?#]/);
2122
+ const pathname = end === -1 ? path : path.slice(0, end);
2123
+ if (pathname.includes("\\"))
2124
+ throw new TypeError("REST paths must not contain backslashes.");
2125
+ for (const segment of pathname.split("/")) {
2126
+ let decoded;
2127
+ try {
2128
+ decoded = decodeURIComponent(segment);
2129
+ } catch {
2130
+ throw new TypeError("REST path has malformed percent-encoding.");
2131
+ }
2132
+ if (decoded === "." || decoded === "..")
2133
+ throw new TypeError("REST paths must not contain '.' or '..' segments.");
2134
+ }
2135
+ }
1948
2136
  var REQUEST_DATA_KEYS = new Set([
1949
2137
  "body",
1950
2138
  "files",
@@ -2029,6 +2217,7 @@ class REST {
2029
2217
  throw new TypeError("REST method is required.");
2030
2218
  if (!path.startsWith("/"))
2031
2219
  throw new TypeError("REST paths must start with '/'.");
2220
+ assertSafePath(path);
2032
2221
  const route = createRouteKey(method, path);
2033
2222
  const files = options.files;
2034
2223
  if (files && files.length > 0 && !(body instanceof FormData))
@@ -2116,13 +2305,19 @@ class REST {
2116
2305
  #headers(body, options) {
2117
2306
  const isFormData = typeof FormData !== "undefined" && body instanceof FormData;
2118
2307
  const headers = { ...options.headers };
2308
+ const set = (name, value) => {
2309
+ for (const key of Object.keys(headers))
2310
+ if (key.toLowerCase() === name.toLowerCase())
2311
+ delete headers[key];
2312
+ headers[name] = value;
2313
+ };
2119
2314
  if (options.auth !== false && this.#token)
2120
- headers["Authorization"] = `Bot ${this.#token}`;
2121
- headers["User-Agent"] = USER_AGENT;
2315
+ set("Authorization", `Bot ${this.#token}`);
2316
+ set("User-Agent", USER_AGENT);
2122
2317
  if (options.reason !== undefined)
2123
- headers["X-Audit-Log-Reason"] = encodeURIComponent(options.reason);
2318
+ set("X-Audit-Log-Reason", encodeURIComponent(options.reason));
2124
2319
  if (!isFormData)
2125
- headers["Content-Type"] = "application/json";
2320
+ set("Content-Type", "application/json");
2126
2321
  return headers;
2127
2322
  }
2128
2323
  #encodeBody(body) {
@@ -2198,7 +2393,7 @@ function cdnURL(path, hash, options = {}) {
2198
2393
  const isAnimated = hash.startsWith("a_") && !options.forceStatic;
2199
2394
  const ext = options.extension ?? (isAnimated ? "gif" : "png");
2200
2395
  const size = options.size ? `?size=${options.size}` : "";
2201
- return `${CDN_BASE}${path}/${hash}.${ext}${size}`;
2396
+ return `${CDN_BASE}${path}/${encodeURIComponent(hash)}.${ext}${size}`;
2202
2397
  }
2203
2398
 
2204
2399
  class User extends BaseStructure {
@@ -2488,10 +2683,10 @@ class GuildMember {
2488
2683
  get permissions() {
2489
2684
  if (this.#suppliedPermissions)
2490
2685
  return this.#suppliedPermissions;
2491
- return new PermissionsBitField(this.#context?.memberPermissions?.(this.guildId, this.user.id, this.roleIds) ?? 0n);
2686
+ return new PermissionsBitField(this.#context?.memberPermissions?.(this.guildId, this.user.id, this.roleIds, undefined, this.timedOutUntil) ?? 0n);
2492
2687
  }
2493
2688
  permissionsIn(channelId) {
2494
- const computed = this.#context?.memberPermissions?.(this.guildId, this.user.id, this.roleIds, channelId);
2689
+ const computed = this.#context?.memberPermissions?.(this.guildId, this.user.id, this.roleIds, channelId, this.timedOutUntil);
2495
2690
  return computed ? new PermissionsBitField(computed) : null;
2496
2691
  }
2497
2692
  #action(name) {
@@ -3634,7 +3829,7 @@ class UserManager extends ResourceManager {
3634
3829
  return this.upsert(new User(data));
3635
3830
  }
3636
3831
  async leaveGuild(guildId) {
3637
- await this.#rest.delete(`/users/@me/guilds/${guildId}`);
3832
+ await this.#rest.delete(Routes.currentUserGuild(guildId));
3638
3833
  }
3639
3834
  async createDM(userId) {
3640
3835
  return this.#rest.post("/users/@me/channels", {
@@ -3923,20 +4118,15 @@ class RoleManager extends ResourceManager {
3923
4118
  }
3924
4119
  async create(options) {
3925
4120
  const { reason, ...payload } = options;
3926
- const data = await this.#rest.post(Routes.guildRoles(this.guildId), {
3927
- ...payload,
3928
- permissions: payload.permissions !== undefined ? String(payload.permissions) : undefined
3929
- }, { reason });
3930
- const role = new Role(data);
3931
- this.set(role.id, role);
3932
- return role;
4121
+ const data = await this.#rest.post(Routes.guildRoles(this.guildId), rolePayload(payload), { reason });
4122
+ return this.#store(data);
3933
4123
  }
3934
4124
  async edit(roleId, options) {
3935
4125
  const { reason, ...payload } = options;
3936
- const data = await this.#rest.patch(Routes.guildRole(this.guildId, roleId), {
3937
- ...payload,
3938
- permissions: payload.permissions !== undefined ? String(payload.permissions) : undefined
3939
- }, { reason });
4126
+ const data = await this.#rest.patch(Routes.guildRole(this.guildId, roleId), rolePayload(payload), { reason });
4127
+ return this.#store(data);
4128
+ }
4129
+ #store(data) {
3940
4130
  const role = new Role(data);
3941
4131
  this.set(role.id, role);
3942
4132
  return role;
@@ -3959,6 +4149,13 @@ class RoleManager extends ResourceManager {
3959
4149
  return this.remove(roleId);
3960
4150
  }
3961
4151
  }
4152
+ function rolePayload(options) {
4153
+ const { permissions, ...rest } = options;
4154
+ return {
4155
+ ...rest,
4156
+ permissions: permissions !== undefined ? String(permissions) : undefined
4157
+ };
4158
+ }
3962
4159
 
3963
4160
  // packages/managers/src/guild-resources.ts
3964
4161
  function withQuery2(path, params) {
@@ -4542,7 +4739,7 @@ class ChannelManager extends Manager {
4542
4739
  await this.#rest.delete(`${Routes.messageReactions(channelId, messageId, emoji)}/@me`);
4543
4740
  }
4544
4741
  async removeReaction(channelId, messageId, emoji, userId) {
4545
- await this.#rest.delete(`${Routes.messageReactions(channelId, messageId, emoji)}/${userId}`);
4742
+ await this.#rest.delete(Routes.messageReactionUser(channelId, messageId, emoji, userId));
4546
4743
  }
4547
4744
  async removeAllReactions(channelId, messageId) {
4548
4745
  await this.#rest.delete(Routes.messageReactionsAll(channelId, messageId));
@@ -4665,7 +4862,26 @@ class GatewaySession {
4665
4862
  return resume ? { type: "resume", ...resume } : { type: "identify" };
4666
4863
  }
4667
4864
  connectURL(fallback) {
4668
- return this.resumeInfo()?.resumeURL ?? fallback;
4865
+ const resume = this.resumeInfo()?.resumeURL;
4866
+ return resume !== undefined && isTrustedGatewayURL(resume, fallback) ? resume : fallback;
4867
+ }
4868
+ }
4869
+ function isTrustedGatewayURL(url, fallback) {
4870
+ let parsed;
4871
+ try {
4872
+ parsed = new URL(url);
4873
+ } catch {
4874
+ return false;
4875
+ }
4876
+ if (parsed.protocol !== "wss:" || parsed.username || parsed.password)
4877
+ return false;
4878
+ const host = parsed.hostname.toLowerCase();
4879
+ if (host === "discord.gg" || host.endsWith(".discord.gg"))
4880
+ return true;
4881
+ try {
4882
+ return host === new URL(fallback).hostname.toLowerCase();
4883
+ } catch {
4884
+ return false;
4669
4885
  }
4670
4886
  }
4671
4887
 
@@ -4941,12 +5157,15 @@ class PlainTextDecoder {
4941
5157
 
4942
5158
  class ZlibStreamDecoder {
4943
5159
  #create;
5160
+ #maxFrameBytes;
4944
5161
  #inflate;
4945
5162
  #chunks = [];
5163
+ #size = 0;
4946
5164
  #failure;
4947
5165
  #pendingReject;
4948
- constructor(create = () => createInflate()) {
5166
+ constructor(create = () => createInflate(), maxFrameBytes = 64 * 1024 * 1024) {
4949
5167
  this.#create = create;
5168
+ this.#maxFrameBytes = maxFrameBytes;
4950
5169
  }
4951
5170
  push(data) {
4952
5171
  if (typeof data === "string")
@@ -4965,6 +5184,7 @@ class ZlibStreamDecoder {
4965
5184
  await this.#awaiting((settle) => inflate.flush(zlibConstants.Z_SYNC_FLUSH, () => settle()));
4966
5185
  const parts = this.#chunks;
4967
5186
  this.#chunks = [];
5187
+ this.#size = 0;
4968
5188
  if (parts.length === 0)
4969
5189
  return [];
4970
5190
  const total = parts.reduce((size, part) => size + part.length, 0);
@@ -4980,6 +5200,7 @@ class ZlibStreamDecoder {
4980
5200
  const inflate = this.#inflate;
4981
5201
  this.#inflate = undefined;
4982
5202
  this.#chunks = [];
5203
+ this.#size = 0;
4983
5204
  this.#failure = undefined;
4984
5205
  this.#pendingReject = undefined;
4985
5206
  if (!inflate)
@@ -5007,7 +5228,17 @@ class ZlibStreamDecoder {
5007
5228
  }
5008
5229
  #open() {
5009
5230
  const inflate = this.#create();
5010
- inflate.on("data", (chunk) => this.#chunks.push(chunk));
5231
+ inflate.on("data", (chunk) => {
5232
+ if (this.#failure)
5233
+ return;
5234
+ this.#size += chunk.length;
5235
+ if (this.#size > this.#maxFrameBytes) {
5236
+ this.#chunks = [];
5237
+ inflate.emit("error", new Error(`Gateway frame inflated past ${this.#maxFrameBytes} bytes.`));
5238
+ return;
5239
+ }
5240
+ this.#chunks.push(chunk);
5241
+ });
5011
5242
  inflate.on("error", (error) => {
5012
5243
  this.#failure = error;
5013
5244
  const reject = this.#pendingReject;
@@ -5250,9 +5481,9 @@ function classifyPayload(payload) {
5250
5481
  }
5251
5482
  function identifyPayload(options) {
5252
5483
  const props = options.properties ?? {};
5253
- const os = props.os ?? "Android";
5254
- const browser = props.browser ?? "Discord Android";
5255
- const device = props.device ?? "Discord Android";
5484
+ const os = props.os ?? process.platform;
5485
+ const browser = props.browser ?? "Lunibee";
5486
+ const device = props.device ?? "Lunibee";
5256
5487
  return {
5257
5488
  op: GatewayOpcodes.Identify,
5258
5489
  d: {
@@ -5357,9 +5588,9 @@ class Gateway {
5357
5588
  heartbeatAckTimeout: 1e4,
5358
5589
  zombieTimeout: 30000,
5359
5590
  properties: {
5360
- os: "Android",
5361
- browser: "Discord Android",
5362
- device: "Discord Android"
5591
+ os: process.platform,
5592
+ browser: "Lunibee",
5593
+ device: "Lunibee"
5363
5594
  },
5364
5595
  presence: {
5365
5596
  status: "online",
@@ -5675,14 +5906,12 @@ class Gateway {
5675
5906
 
5676
5907
  // packages/core/src/index.ts
5677
5908
  class EventEmitter2 {
5678
- #listeners = new Map;
5909
+ #listeners = {};
5910
+ redactSecrets = (text) => text;
5679
5911
  on(event, listener) {
5680
5912
  if (typeof listener !== "function")
5681
5913
  throw new TypeError("Event listener must be a function.");
5682
- let listeners = this.#listeners.get(event);
5683
- if (!listeners)
5684
- this.#listeners.set(event, listeners = new Set);
5685
- listeners.add(listener);
5914
+ (this.#listeners[event] ??= new Set).add(listener);
5686
5915
  return this;
5687
5916
  }
5688
5917
  once(event, listener) {
@@ -5693,7 +5922,7 @@ class EventEmitter2 {
5693
5922
  return this.on(event, wrapped);
5694
5923
  }
5695
5924
  off(event, listener) {
5696
- this.#listeners.get(event)?.delete(listener);
5925
+ this.#listeners[event]?.delete(listener);
5697
5926
  return this;
5698
5927
  }
5699
5928
  removeListener(event, listener) {
@@ -5701,13 +5930,13 @@ class EventEmitter2 {
5701
5930
  }
5702
5931
  removeAllListeners(event) {
5703
5932
  if (event === undefined)
5704
- this.#listeners.clear();
5933
+ this.#listeners = {};
5705
5934
  else
5706
- this.#listeners.delete(event);
5935
+ delete this.#listeners[event];
5707
5936
  return this;
5708
5937
  }
5709
5938
  emit(event, ...args) {
5710
- const listeners = this.#listeners.get(event);
5939
+ const listeners = this.#listeners[event];
5711
5940
  if (!listeners?.size)
5712
5941
  return false;
5713
5942
  for (const listener of [...listeners]) {
@@ -5723,28 +5952,27 @@ class EventEmitter2 {
5723
5952
  }
5724
5953
  #handleError(event, error) {
5725
5954
  const normalized = error instanceof Error ? error : new Error(String(error), { cause: error });
5726
- const listeners = event === "error" /* Error */ ? [] : [
5727
- ...this.#listeners.get("error" /* Error */) ?? []
5728
- ];
5955
+ const errorListeners = this.#listeners["error" /* Error */];
5956
+ const listeners = event === "error" /* Error */ ? [] : [...errorListeners ?? []];
5729
5957
  if (listeners.length === 0)
5730
- return warnListenerError(event, normalized);
5958
+ return warnListenerError(event, normalized, this.redactSecrets);
5731
5959
  for (const listener of listeners) {
5732
5960
  try {
5733
5961
  const result = listener(normalized);
5734
5962
  if (result && typeof result.then === "function")
5735
- Promise.resolve(result).catch((failure) => warnListenerError("error" /* Error */, failure));
5963
+ Promise.resolve(result).catch((failure) => warnListenerError("error" /* Error */, failure, this.redactSecrets));
5736
5964
  } catch (failure) {
5737
- warnListenerError("error" /* Error */, failure);
5965
+ warnListenerError("error" /* Error */, failure, this.redactSecrets);
5738
5966
  }
5739
5967
  }
5740
5968
  }
5741
5969
  }
5742
- function warnListenerError(event, error) {
5970
+ function warnListenerError(event, error, redact = (text) => text) {
5743
5971
  const failure = error instanceof Error ? error : new Error(String(error));
5744
- process.emitWarning(`A "${String(event)}" listener threw and no error listener handled it: ${failure.message}`, {
5972
+ process.emitWarning(redact(`A "${String(event)}" listener threw and no error listener handled it: ${failure.message}`), {
5745
5973
  type: "LunibeeWarning",
5746
5974
  code: "LUNIBEE_UNHANDLED_LISTENER_ERROR",
5747
- detail: failure.stack
5975
+ detail: failure.stack === undefined ? undefined : redact(failure.stack)
5748
5976
  });
5749
5977
  }
5750
5978
 
@@ -5766,6 +5994,10 @@ class Client extends EventEmitter2 {
5766
5994
  user;
5767
5995
  readyAt;
5768
5996
  state = "idle";
5997
+ redactSecrets = (text) => {
5998
+ const token = this.options.token;
5999
+ return token && token.length >= 8 ? text.split(token).join("[token]") : text;
6000
+ };
5769
6001
  get token() {
5770
6002
  return this.state === "destroyed" ? null : this.options.token ?? null;
5771
6003
  }
@@ -5812,7 +6044,22 @@ class Client extends EventEmitter2 {
5812
6044
  this.stageInstances = new StageInstanceManager(this.rest);
5813
6045
  const placeholderAppCommands = new ApplicationCommandManager(this.rest, "0");
5814
6046
  this.application = { commands: placeholderAppCommands };
5815
- this.#resourceContext = {
6047
+ this.#resourceContext = this.#createResourceContext();
6048
+ this.guilds.attachContext(this.#resourceContext);
6049
+ this.#gateway = new Gateway({
6050
+ token: options.token,
6051
+ intents: options.intents,
6052
+ ...options.gateway
6053
+ });
6054
+ this.#wireLifecycle();
6055
+ this.#wireMessages();
6056
+ this.#wireGuilds();
6057
+ this.#wireGuildFeatures();
6058
+ this.#wireChannels();
6059
+ this.#wireMisc();
6060
+ }
6061
+ #createResourceContext() {
6062
+ return {
5816
6063
  sendMessage: (channelId, options) => this.channels.send(channelId, options),
5817
6064
  editMessage: (channelId, messageId, options) => this.channels.editMessage(channelId, messageId, options),
5818
6065
  deleteMessage: (channelId, messageId, reason) => this.channels.deleteMessage(channelId, messageId, reason),
@@ -5826,7 +6073,7 @@ class Client extends EventEmitter2 {
5826
6073
  pinMessage: (channelId, messageId, reason) => this.channels.pinMessage(channelId, messageId, reason),
5827
6074
  unpinMessage: (channelId, messageId, reason) => this.channels.unpinMessage(channelId, messageId, reason),
5828
6075
  collectInteractions: (options) => this.createCollector("interactionCreate" /* InteractionCreate */, options),
5829
- memberPermissions: (guildId, memberId, roleIds, channelId) => this.#memberPermissions(guildId, memberId, roleIds, channelId),
6076
+ memberPermissions: (guildId, memberId, roleIds, channelId, timedOutUntil) => this.#memberPermissions(guildId, memberId, roleIds, channelId, timedOutUntil),
5830
6077
  kickMember: (guildId, userId, reason) => this.guilds.members(guildId).kick(userId, reason),
5831
6078
  banMember: (guildId, userId, options) => this.guilds.members(guildId).ban(userId, options),
5832
6079
  editMember: (guildId, userId, options, reason) => this.guilds.members(guildId).edit(userId, options, reason),
@@ -5849,12 +6096,8 @@ class Client extends EventEmitter2 {
5849
6096
  return this.channels.permissionOverwrites(channelId).update(targetId, bits, options);
5850
6097
  }
5851
6098
  };
5852
- this.guilds.attachContext(this.#resourceContext);
5853
- this.#gateway = new Gateway({
5854
- token: options.token,
5855
- intents: options.intents,
5856
- ...options.gateway
5857
- });
6099
+ }
6100
+ #wireLifecycle() {
5858
6101
  this.#gateway.on("READY", (data) => {
5859
6102
  const ready = data;
5860
6103
  this.user = ready.user;
@@ -5880,6 +6123,8 @@ class Client extends EventEmitter2 {
5880
6123
  this.state = "idle";
5881
6124
  this.emit("close" /* Close */, data);
5882
6125
  });
6126
+ }
6127
+ #wireMessages() {
5883
6128
  this.#gateway.on("MESSAGE_CREATE", (data) => {
5884
6129
  const payload = data;
5885
6130
  const message = new Message(payload, this.#resourceContext);
@@ -5927,6 +6172,8 @@ class Client extends EventEmitter2 {
5927
6172
  this.#gateway.on("MESSAGE_REACTION_REMOVE_EMOJI", (data) => this.emit("messageReactionRemoveEmoji" /* MessageReactionRemoveEmoji */, data));
5928
6173
  this.#gateway.on("MESSAGE_POLL_VOTE_ADD", (data) => this.emit("messagePollVoteAdd" /* MessagePollVoteAdd */, data));
5929
6174
  this.#gateway.on("MESSAGE_POLL_VOTE_REMOVE", (data) => this.emit("messagePollVoteRemove" /* MessagePollVoteRemove */, data));
6175
+ }
6176
+ #wireGuilds() {
5930
6177
  this.#gateway.on("GUILD_CREATE", (data) => {
5931
6178
  const payload = data;
5932
6179
  if (payload.unavailable) {
@@ -6027,6 +6274,8 @@ class Client extends EventEmitter2 {
6027
6274
  roles.delete(event.role_id);
6028
6275
  this.emit("guildRoleDelete" /* GuildRoleDelete */, event, removed);
6029
6276
  });
6277
+ }
6278
+ #wireGuildFeatures() {
6030
6279
  this.#gateway.on("GUILD_EMOJIS_UPDATE", (data) => {
6031
6280
  const event = data;
6032
6281
  let previous = null;
@@ -6123,6 +6372,8 @@ class Client extends EventEmitter2 {
6123
6372
  this.emit("autoModerationRuleDelete" /* AutoModerationRuleDelete */, rule);
6124
6373
  });
6125
6374
  this.#gateway.on("AUTO_MODERATION_ACTION_EXECUTION", (data) => this.emit("autoModerationActionExecution" /* AutoModerationActionExecution */, data));
6375
+ }
6376
+ #wireChannels() {
6126
6377
  this.#gateway.on("CHANNEL_CREATE", (data) => {
6127
6378
  const channel = this.channels.upsert(data);
6128
6379
  this.emit("channelCreate" /* ChannelCreate */, channel);
@@ -6190,6 +6441,8 @@ class Client extends EventEmitter2 {
6190
6441
  this.emit("inviteDelete" /* InviteDelete */, invite);
6191
6442
  });
6192
6443
  this.#gateway.on("WEBHOOKS_UPDATE", (data) => this.emit("webhooksUpdate" /* WebhooksUpdate */, data));
6444
+ }
6445
+ #wireMisc() {
6193
6446
  this.#gateway.on("VOICE_STATE_UPDATE", (data) => {
6194
6447
  const state = data;
6195
6448
  if (state.guild_id)
@@ -6265,7 +6518,7 @@ class Client extends EventEmitter2 {
6265
6518
  get resourceContext() {
6266
6519
  return this.#resourceContext;
6267
6520
  }
6268
- #memberPermissions(guildId, memberId, roleIds, channelId) {
6521
+ #memberPermissions(guildId, memberId, roleIds, channelId, timedOutUntil) {
6269
6522
  const guild = this.guilds.get(guildId);
6270
6523
  if (!guild)
6271
6524
  return null;
@@ -6282,7 +6535,8 @@ class Client extends EventEmitter2 {
6282
6535
  memberId,
6283
6536
  memberRoleIds: [...roleIds],
6284
6537
  roles: this.guilds.roles(guildId).values(),
6285
- overwrites: channel?.permissionOverwrites
6538
+ overwrites: channel?.permissionOverwrites,
6539
+ timedOutUntil
6286
6540
  });
6287
6541
  }
6288
6542
  permissionsFor(memberId, guildOrChannelId) {
@@ -6303,7 +6557,8 @@ class Client extends EventEmitter2 {
6303
6557
  memberId,
6304
6558
  memberRoleIds: member.roleIds,
6305
6559
  roles: this.guilds.roles(guildId).values(),
6306
- overwrites: channel?.permissionOverwrites
6560
+ overwrites: channel?.permissionOverwrites,
6561
+ timedOutUntil: member.timedOutUntil
6307
6562
  });
6308
6563
  }
6309
6564
  fetchDefaultSoundboardSounds() {
@@ -6351,10 +6606,10 @@ class Client extends EventEmitter2 {
6351
6606
  return Promise.reject(new Error("Client is unauthenticated."));
6352
6607
  return this.rest.delete(Routes.interactionOriginalResponse(this.user.id, token));
6353
6608
  }
6354
- followUpInteraction(token, data) {
6609
+ async followUpInteraction(token, data) {
6355
6610
  if (!this.user)
6356
6611
  return Promise.reject(new Error("Client is unauthenticated."));
6357
- return this.rest.post(`/webhooks/${this.user.id}/${token}`, toRequest(data, this.options.allowedMentions));
6612
+ return this.rest.post(Routes.webhook(this.user.id, token), toRequest(data, this.options.allowedMentions));
6358
6613
  }
6359
6614
  interactionWebhookMessage(method, applicationId, token, messageId, data) {
6360
6615
  const path = messageId === "@original" ? Routes.interactionOriginalResponse(applicationId, token) : Routes.webhookMessage(applicationId, token, messageId);
@@ -6364,11 +6619,11 @@ class Client extends EventEmitter2 {
6364
6619
  return this.rest.patch(path, data ? toRequest(data, this.options.allowedMentions) : data);
6365
6620
  return this.rest.delete(path);
6366
6621
  }
6367
- fetchWebhook(id, token) {
6368
- return this.rest.get(token ? `/webhooks/${id}/${token}` : `/webhooks/${id}`);
6622
+ async fetchWebhook(id, token) {
6623
+ return this.rest.get(Routes.webhook(id, token));
6369
6624
  }
6370
- fetchGuildPreview(guildId) {
6371
- return this.rest.get(`/guilds/${guildId}/preview`);
6625
+ async fetchGuildPreview(guildId) {
6626
+ return this.rest.get(Routes.guildPreview(guildId));
6372
6627
  }
6373
6628
  fetchVoiceRegions() {
6374
6629
  return this.rest.get("/voice/regions");
@@ -6382,8 +6637,8 @@ class Client extends EventEmitter2 {
6382
6637
  const qs = query.toString();
6383
6638
  return this.rest.get(`/invites/${encodeURIComponent(code)}${qs ? `?${qs}` : ""}`);
6384
6639
  }
6385
- fetchSticker(id) {
6386
- return this.rest.get(`/stickers/${id}`);
6640
+ async fetchSticker(id) {
6641
+ return this.rest.get(Routes.sticker(id));
6387
6642
  }
6388
6643
  fetchPremiumStickerPacks() {
6389
6644
  return this.rest.get(`/sticker-packs`);
@@ -6424,4 +6679,4 @@ export {
6424
6679
  resolveGatewayIntents
6425
6680
  };
6426
6681
 
6427
- //# debugId=A8C0111D9C7EBB3664756E2164756E21
6682
+ //# debugId=9FDCE9C1C9B0DB0164756E2164756E21