lunibee 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +3 -3
  2. package/dist/builders/commands.d.ts +37 -0
  3. package/dist/builders/components.d.ts +19 -12
  4. package/dist/builders/embed.d.ts +3 -1
  5. package/dist/builders/index.d.ts +1 -1
  6. package/dist/builders/index.js +146 -19
  7. package/dist/builders/index.js.map +8 -7
  8. package/dist/collection/index.d.ts +30 -0
  9. package/dist/collection/index.js +78 -5
  10. package/dist/collection/index.js.map +4 -4
  11. package/dist/core/events.d.ts +2 -0
  12. package/dist/core/index.d.ts +38 -0
  13. package/dist/core/index.js +754 -175
  14. package/dist/core/index.js.map +24 -22
  15. package/dist/core/permissions.d.ts +112 -53
  16. package/dist/formatters/index.d.ts +43 -3
  17. package/dist/formatters/index.js +64 -1
  18. package/dist/formatters/index.js.map +3 -3
  19. package/dist/handlers/index.js.map +2 -2
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.js +1762 -291
  22. package/dist/index.js.map +43 -38
  23. package/dist/managers/emoji.d.ts +38 -0
  24. package/dist/managers/guild.d.ts +112 -1
  25. package/dist/managers/index.d.ts +31 -1
  26. package/dist/managers/index.js +803 -77
  27. package/dist/managers/index.js.map +21 -20
  28. package/dist/rest/index.d.ts +101 -11
  29. package/dist/rest/index.js +301 -45
  30. package/dist/rest/index.js.map +8 -6
  31. package/dist/rest/redis.d.ts +37 -0
  32. package/dist/rest/routes.d.ts +22 -0
  33. package/dist/rest/store.d.ts +38 -0
  34. package/dist/rest/webhook.d.ts +2 -2
  35. package/dist/sharding/cluster.d.ts +61 -0
  36. package/dist/sharding/index.d.ts +8 -0
  37. package/dist/sharding/index.js +286 -18
  38. package/dist/sharding/index.js.map +8 -7
  39. package/dist/structures/audit-log.d.ts +26 -0
  40. package/dist/structures/base.d.ts +32 -0
  41. package/dist/structures/index.d.ts +29 -1
  42. package/dist/structures/index.js +1022 -86
  43. package/dist/structures/index.js.map +14 -10
  44. package/dist/structures/resources.d.ts +192 -4
  45. package/dist/types/index.d.ts +76 -0
  46. package/dist/types/index.js.map +2 -2
  47. package/dist/utils/index.js.map +2 -2
  48. package/dist/voice/index.d.ts +88 -0
  49. package/dist/voice/index.js +204 -5
  50. package/dist/voice/index.js.map +3 -3
  51. package/dist/ws/index.d.ts +40 -1
  52. package/dist/ws/index.js +102 -18
  53. package/dist/ws/index.js.map +4 -4
  54. package/package.json +16 -16
  55. package/dist/structures/permissions.d.ts +0 -73
package/dist/index.js CHANGED
@@ -107,58 +107,57 @@ var Permissions = {
107
107
  SendPolls: 1n << 49n,
108
108
  UseExternalApps: 1n << 50n
109
109
  };
110
- var PermissionFlagsBits;
111
- ((PermissionFlagsBits2) => {
112
- PermissionFlagsBits2["CreateInstantInvite"] = "1";
113
- PermissionFlagsBits2["KickMembers"] = "2";
114
- PermissionFlagsBits2["BanMembers"] = "4";
115
- PermissionFlagsBits2["Administrator"] = "8";
116
- PermissionFlagsBits2["ManageChannels"] = "16";
117
- PermissionFlagsBits2["ManageGuild"] = "32";
118
- PermissionFlagsBits2["AddReactions"] = "64";
119
- PermissionFlagsBits2["ViewAuditLog"] = "128";
120
- PermissionFlagsBits2["PrioritySpeaker"] = "256";
121
- PermissionFlagsBits2["Stream"] = "512";
122
- PermissionFlagsBits2["ViewChannel"] = "1024";
123
- PermissionFlagsBits2["SendMessages"] = "2048";
124
- PermissionFlagsBits2["SendTTSMessages"] = "4096";
125
- PermissionFlagsBits2["ManageMessages"] = "8192";
126
- PermissionFlagsBits2["EmbedLinks"] = "16384";
127
- PermissionFlagsBits2["AttachFiles"] = "32768";
128
- PermissionFlagsBits2["ReadMessageHistory"] = "65536";
129
- PermissionFlagsBits2["MentionEveryone"] = "131072";
130
- PermissionFlagsBits2["UseExternalEmojis"] = "262144";
131
- PermissionFlagsBits2["ViewGuildInsights"] = "524288";
132
- PermissionFlagsBits2["Connect"] = "1048576";
133
- PermissionFlagsBits2["Speak"] = "2097152";
134
- PermissionFlagsBits2["MuteMembers"] = "4194304";
135
- PermissionFlagsBits2["DeafenMembers"] = "8388608";
136
- PermissionFlagsBits2["MoveMembers"] = "16777216";
137
- PermissionFlagsBits2["UseVAD"] = "33554432";
138
- PermissionFlagsBits2["ChangeNickname"] = "67108864";
139
- PermissionFlagsBits2["ManageNicknames"] = "134217728";
140
- PermissionFlagsBits2["ManageRoles"] = "268435456";
141
- PermissionFlagsBits2["ManageWebhooks"] = "536870912";
142
- PermissionFlagsBits2["ManageGuildExpressions"] = "1073741824";
143
- PermissionFlagsBits2["UseApplicationCommands"] = "2147483648";
144
- PermissionFlagsBits2["RequestToSpeak"] = "4294967296";
145
- PermissionFlagsBits2["ManageEvents"] = "8589934592";
146
- PermissionFlagsBits2["ManageThreads"] = "17179869184";
147
- PermissionFlagsBits2["CreatePublicThreads"] = "34359738368";
148
- PermissionFlagsBits2["CreatePrivateThreads"] = "68719476736";
149
- PermissionFlagsBits2["UseExternalStickers"] = "137438953472";
150
- PermissionFlagsBits2["SendMessagesInThreads"] = "274877906944";
151
- PermissionFlagsBits2["UseEmbeddedActivities"] = "549755813888";
152
- PermissionFlagsBits2["ModerateMembers"] = "1099511627776";
153
- PermissionFlagsBits2["ViewCreatorMonetizationAnalytics"] = "2199023255552";
154
- PermissionFlagsBits2["UseSoundboard"] = "4398046511104";
155
- PermissionFlagsBits2["CreateGuildExpressions"] = "8796093022208";
156
- PermissionFlagsBits2["CreateEvents"] = "17592186044416";
157
- PermissionFlagsBits2["UseExternalSounds"] = "35184372088832";
158
- PermissionFlagsBits2["SendVoiceMessages"] = "70368744177664";
159
- PermissionFlagsBits2["SendPolls"] = "562949953421312";
160
- PermissionFlagsBits2["UseExternalApps"] = "1125899906842624";
161
- })(PermissionFlagsBits ||= {});
110
+ var PermissionFlagsBits = {
111
+ CreateInstantInvite: 1n << 0n,
112
+ KickMembers: 1n << 1n,
113
+ BanMembers: 1n << 2n,
114
+ Administrator: 1n << 3n,
115
+ ManageChannels: 1n << 4n,
116
+ ManageGuild: 1n << 5n,
117
+ AddReactions: 1n << 6n,
118
+ ViewAuditLog: 1n << 7n,
119
+ PrioritySpeaker: 1n << 8n,
120
+ Stream: 1n << 9n,
121
+ ViewChannel: 1n << 10n,
122
+ SendMessages: 1n << 11n,
123
+ SendTTSMessages: 1n << 12n,
124
+ ManageMessages: 1n << 13n,
125
+ EmbedLinks: 1n << 14n,
126
+ AttachFiles: 1n << 15n,
127
+ ReadMessageHistory: 1n << 16n,
128
+ MentionEveryone: 1n << 17n,
129
+ UseExternalEmojis: 1n << 18n,
130
+ ViewGuildInsights: 1n << 19n,
131
+ Connect: 1n << 20n,
132
+ Speak: 1n << 21n,
133
+ MuteMembers: 1n << 22n,
134
+ DeafenMembers: 1n << 23n,
135
+ MoveMembers: 1n << 24n,
136
+ UseVAD: 1n << 25n,
137
+ ChangeNickname: 1n << 26n,
138
+ ManageNicknames: 1n << 27n,
139
+ ManageRoles: 1n << 28n,
140
+ ManageWebhooks: 1n << 29n,
141
+ ManageGuildExpressions: 1n << 30n,
142
+ UseApplicationCommands: 1n << 31n,
143
+ RequestToSpeak: 1n << 32n,
144
+ ManageEvents: 1n << 33n,
145
+ ManageThreads: 1n << 34n,
146
+ CreatePublicThreads: 1n << 35n,
147
+ CreatePrivateThreads: 1n << 36n,
148
+ UseExternalStickers: 1n << 37n,
149
+ SendMessagesInThreads: 1n << 38n,
150
+ UseEmbeddedActivities: 1n << 39n,
151
+ ModerateMembers: 1n << 40n,
152
+ ViewCreatorMonetizationAnalytics: 1n << 41n,
153
+ UseSoundboard: 1n << 42n,
154
+ CreateGuildExpressions: 1n << 43n,
155
+ CreateEvents: 1n << 44n,
156
+ UseExternalSounds: 1n << 45n,
157
+ SendVoiceMessages: 1n << 46n,
158
+ SendPolls: 1n << 49n,
159
+ UseExternalApps: 1n << 50n
160
+ };
162
161
 
163
162
  class PermissionSet {
164
163
  bitfield;
@@ -403,7 +402,7 @@ class PermissionSet {
403
402
  if (permission in Permissions)
404
403
  return Permissions[permission];
405
404
  if (permission in PermissionFlagsBits)
406
- return BigInt(PermissionFlagsBits[permission]);
405
+ return PermissionFlagsBits[permission];
407
406
  const lower = permission.charAt(0).toLowerCase() + permission.slice(1);
408
407
  if (lower in Permission)
409
408
  return Permission[lower];
@@ -424,6 +423,8 @@ class PermissionsBitField extends PermissionSet {
424
423
  var ClientEvent;
425
424
  ((ClientEvent2) => {
426
425
  ClientEvent2["Ready"] = "ready";
426
+ ClientEvent2["Resumed"] = "resumed";
427
+ ClientEvent2["InvalidSession"] = "invalidSession";
427
428
  ClientEvent2["Raw"] = "raw";
428
429
  ClientEvent2["Error"] = "error";
429
430
  ClientEvent2["Open"] = "open";
@@ -486,6 +487,76 @@ var ClientEvent;
486
487
  ClientEvent2["TypingStart"] = "typingStart";
487
488
  ClientEvent2["InteractionCreate"] = "interactionCreate";
488
489
  })(ClientEvent ||= {});
490
+ // packages/core/src/collector.ts
491
+ import { EventEmitter } from "events";
492
+
493
+ class Collector extends EventEmitter {
494
+ collected = new Map;
495
+ options;
496
+ ended = false;
497
+ endReason;
498
+ totalProcessed = 0;
499
+ #timeoutTimer;
500
+ constructor(options = {}) {
501
+ super();
502
+ this.options = options;
503
+ if (options.time && options.time > 0) {
504
+ this.#timeoutTimer = setTimeout(() => {
505
+ this.stop("time");
506
+ }, options.time);
507
+ }
508
+ }
509
+ async handle(key, item) {
510
+ if (this.ended)
511
+ return false;
512
+ this.totalProcessed++;
513
+ const reachedProcessed = !!this.options.maxProcessed && this.totalProcessed >= this.options.maxProcessed;
514
+ let passed = true;
515
+ if (this.options.filter)
516
+ passed = !!await this.options.filter(item);
517
+ if (this.ended)
518
+ return false;
519
+ if (!passed) {
520
+ if (reachedProcessed)
521
+ this.stop("processedLimit");
522
+ return false;
523
+ }
524
+ this.collected.set(key, item);
525
+ this.emit("collect", item);
526
+ if (this.options.max && this.collected.size >= this.options.max) {
527
+ this.stop("limit");
528
+ return true;
529
+ }
530
+ if (reachedProcessed) {
531
+ this.stop("processedLimit");
532
+ return true;
533
+ }
534
+ return true;
535
+ }
536
+ stop(reason = "user") {
537
+ if (this.ended)
538
+ return;
539
+ this.ended = true;
540
+ this.endReason = reason;
541
+ if (this.#timeoutTimer)
542
+ clearTimeout(this.#timeoutTimer);
543
+ this.emit("end", this.collected, reason);
544
+ this.removeAllListeners();
545
+ }
546
+ next() {
547
+ return new Promise((resolve, reject) => {
548
+ if (this.ended) {
549
+ return reject(new Error(`Collector already ended: ${this.endReason ?? "unknown"}`));
550
+ }
551
+ this.once("collect", (item) => {
552
+ resolve(item);
553
+ });
554
+ this.once("end", (_collected, reason) => {
555
+ reject(new Error(`Collector ended before item was collected: ${reason}`));
556
+ });
557
+ });
558
+ }
559
+ }
489
560
  // packages/types/src/index.ts
490
561
  var GatewayIntentBits = {
491
562
  Guilds: 1 << 0,
@@ -587,6 +658,14 @@ var ChannelType = {
587
658
  GuildForum: 15,
588
659
  GuildMedia: 16
589
660
  };
661
+ var ButtonStyle = {
662
+ Primary: 1,
663
+ Secondary: 2,
664
+ Success: 3,
665
+ Danger: 4,
666
+ Link: 5,
667
+ Premium: 6
668
+ };
590
669
  var InteractionResponseType = {
591
670
  Pong: 1,
592
671
  ChannelMessage: 4,
@@ -687,10 +766,14 @@ class Cache {
687
766
  const expiresAt = this.#ttl > 0 ? Date.now() + this.#ttl : 0;
688
767
  this.#entries.delete(key);
689
768
  this.#entries.set(key, { value, expiresAt });
690
- while (this.#entries.size > this.#maxSize) {
691
- const oldest = this.#entries.firstKey();
692
- if (oldest !== undefined)
693
- this.#entries.delete(oldest);
769
+ if (this.#maxSize !== Infinity) {
770
+ while (this.#entries.size > this.#maxSize) {
771
+ const oldest = this.#entries.firstKey();
772
+ if (oldest !== undefined)
773
+ this.#entries.delete(oldest);
774
+ else
775
+ break;
776
+ }
694
777
  }
695
778
  return this;
696
779
  }
@@ -874,6 +957,75 @@ class Collection extends Map {
874
957
  }
875
958
  return result;
876
959
  }
960
+ partition(predicate) {
961
+ const pass = new Collection;
962
+ const fail = new Collection;
963
+ for (const [key, value] of this) {
964
+ if (predicate(value, key, this))
965
+ pass.set(key, value);
966
+ else
967
+ fail.set(key, value);
968
+ }
969
+ return [pass, fail];
970
+ }
971
+ tap(fn) {
972
+ fn(this);
973
+ return this;
974
+ }
975
+ flatMap(transform) {
976
+ const result = [];
977
+ for (const [key, value] of this) {
978
+ for (const item of transform(value, key, this))
979
+ result.push(item);
980
+ }
981
+ return result;
982
+ }
983
+ reduce(fn, initialValue) {
984
+ let acc = initialValue;
985
+ for (const [key, value] of this)
986
+ acc = fn(acc, value, key, this);
987
+ return acc;
988
+ }
989
+ sorted(comparator) {
990
+ const decorated = [...this.entries()].map((entry, index) => ({
991
+ entry,
992
+ index
993
+ }));
994
+ if (comparator)
995
+ decorated.sort((x, y) => {
996
+ const comparison = comparator(x.entry[1], y.entry[1], x.entry[0], y.entry[0]);
997
+ return comparison !== 0 ? comparison : x.index - y.index;
998
+ });
999
+ const result = new Collection;
1000
+ for (const { entry } of decorated)
1001
+ result.set(entry[0], entry[1]);
1002
+ return result;
1003
+ }
1004
+ random() {
1005
+ const arr = [...this.values()];
1006
+ if (!arr.length)
1007
+ return;
1008
+ return arr[Math.floor(Math.random() * arr.length)];
1009
+ }
1010
+ randomKey() {
1011
+ const arr = [...this.keys()];
1012
+ if (!arr.length)
1013
+ return;
1014
+ return arr[Math.floor(Math.random() * arr.length)];
1015
+ }
1016
+ at(index) {
1017
+ const arr = [...this.values()];
1018
+ const i = index < 0 ? arr.length + index : index;
1019
+ return arr[i];
1020
+ }
1021
+ keyAt(index) {
1022
+ const arr = [...this.keys()];
1023
+ const i = index < 0 ? arr.length + index : index;
1024
+ return arr[i];
1025
+ }
1026
+ toJSON() {
1027
+ return [...this.entries()];
1028
+ }
877
1029
  }
878
1030
 
879
1031
  // packages/managers/src/base.ts
@@ -945,7 +1097,7 @@ class ResourceManager extends Manager {
945
1097
  // packages/rest/package.json
946
1098
  var package_default = {
947
1099
  name: "@lunibee/rest",
948
- version: "0.1.6",
1100
+ version: "0.1.7",
949
1101
  type: "module",
950
1102
  module: "./src/index.ts",
951
1103
  types: "./src/index.ts",
@@ -954,6 +1106,45 @@ var package_default = {
954
1106
  }
955
1107
  };
956
1108
 
1109
+ // packages/rest/src/store.ts
1110
+ class MemoryRateLimitStore {
1111
+ #buckets = new Map;
1112
+ #routeBuckets = new Map;
1113
+ #globalResetAt = 0;
1114
+ static #PRUNE_INTERVAL = 60000;
1115
+ #lastPruneAt = 0;
1116
+ getBucketHash(route) {
1117
+ return this.#routeBuckets.get(route);
1118
+ }
1119
+ setBucketHash(route, hash) {
1120
+ this.#routeBuckets.set(route, hash);
1121
+ }
1122
+ getBucket(key) {
1123
+ return this.#buckets.get(key);
1124
+ }
1125
+ updateBucket(key, state) {
1126
+ this.#buckets.set(key, state);
1127
+ const now = Date.now();
1128
+ if (now - this.#lastPruneAt >= MemoryRateLimitStore.#PRUNE_INTERVAL) {
1129
+ this.#lastPruneAt = now;
1130
+ this.prune();
1131
+ }
1132
+ }
1133
+ prune(maxAge = 0) {
1134
+ const cutoff = Date.now() - Math.max(0, maxAge);
1135
+ for (const [key, state] of this.#buckets) {
1136
+ if (state.resetAt <= cutoff)
1137
+ this.#buckets.delete(key);
1138
+ }
1139
+ }
1140
+ getGlobalReset() {
1141
+ return this.#globalResetAt;
1142
+ }
1143
+ setGlobalReset(resetAt) {
1144
+ this.#globalResetAt = resetAt;
1145
+ }
1146
+ }
1147
+
957
1148
  // packages/rest/src/routes.ts
958
1149
  var Routes = {
959
1150
  user: () => "/users/@me",
@@ -999,13 +1190,122 @@ var Routes = {
999
1190
  guildAutoModerationRule: (guildId, ruleId) => `/guilds/${snowflake(guildId, "Guild ID")}/auto-moderation/rules/${snowflake(ruleId, "Rule ID")}`,
1000
1191
  voiceRegions: () => "/voice/regions",
1001
1192
  gateway: () => "/gateway",
1002
- gatewayBot: () => "/gateway/bot"
1193
+ gatewayBot: () => "/gateway/bot",
1194
+ guildAuditLog: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/audit-logs`,
1195
+ guildMembers: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/members`,
1196
+ guildWelcomeScreen: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/welcome-screen`,
1197
+ guildOnboarding: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/onboarding`,
1198
+ guildPrune: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/prune`,
1199
+ stageInstances: () => "/stage-instances",
1200
+ stageInstanceByChannel: (channelId) => `/stage-instances/${snowflake(channelId, "Channel ID")}`,
1201
+ invite: (code) => `/invites/${encodeURIComponent(code)}`,
1202
+ guildVanity: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/vanity-url`,
1203
+ guildEmoji: (guildId, emojiId) => emojiId ? `/guilds/${snowflake(guildId, "Guild ID")}/emojis/${snowflake(emojiId, "Emoji ID")}` : `/guilds/${snowflake(guildId, "Guild ID")}/emojis`,
1204
+ applicationEmoji: (applicationId, emojiId) => emojiId ? `/applications/${snowflake(applicationId, "Application ID")}/emojis/${snowflake(emojiId, "Emoji ID")}` : `/applications/${snowflake(applicationId, "Application ID")}/emojis`
1003
1205
  };
1004
1206
  function snowflake(value, field) {
1005
1207
  if (!/^\d{1,20}$/.test(value))
1006
1208
  throw new TypeError(`${field} must be a valid Discord snowflake.`);
1007
1209
  return value;
1008
1210
  }
1211
+ // packages/rest/src/redis.ts
1212
+ class RedisRateLimitStore {
1213
+ #client;
1214
+ #prefix;
1215
+ #onErrorCallback;
1216
+ #lastError;
1217
+ constructor(options) {
1218
+ this.#client = options.client;
1219
+ this.#prefix = options.prefix ?? "lunibee:rest:";
1220
+ this.#onErrorCallback = options.onError;
1221
+ }
1222
+ get lastError() {
1223
+ return this.#lastError;
1224
+ }
1225
+ isHealthy() {
1226
+ return this.#lastError === undefined;
1227
+ }
1228
+ #onError(operation, error) {
1229
+ this.#lastError = error;
1230
+ console.warn(`[lunibee/rest] Redis rate-limit store ${operation} failed; ` + `falling back to local limiting for this call.`, error);
1231
+ try {
1232
+ this.#onErrorCallback?.(operation, error);
1233
+ } catch {}
1234
+ }
1235
+ #markHealthy() {
1236
+ this.#lastError = undefined;
1237
+ }
1238
+ async getBucketHash(route) {
1239
+ try {
1240
+ const hash = await this.#client.get(`${this.#prefix}route:${route}`);
1241
+ this.#markHealthy();
1242
+ return hash ?? undefined;
1243
+ } catch (error) {
1244
+ this.#onError("getBucketHash", error);
1245
+ return;
1246
+ }
1247
+ }
1248
+ async setBucketHash(route, hash) {
1249
+ try {
1250
+ await this.#client.set(`${this.#prefix}route:${route}`, hash, "EX", 604800);
1251
+ this.#markHealthy();
1252
+ } catch (error) {
1253
+ this.#onError("setBucketHash", error);
1254
+ }
1255
+ }
1256
+ async getBucket(key) {
1257
+ try {
1258
+ const data = await this.#client.get(`${this.#prefix}bucket:${key}`);
1259
+ this.#markHealthy();
1260
+ if (!data)
1261
+ return;
1262
+ return JSON.parse(data);
1263
+ } catch (error) {
1264
+ this.#onError("getBucket", error);
1265
+ return;
1266
+ }
1267
+ }
1268
+ async updateBucket(key, state) {
1269
+ const bucketKey = `${this.#prefix}bucket:${key}`;
1270
+ const ttl = Math.ceil((state.resetAt - Date.now()) / 1000);
1271
+ try {
1272
+ if (ttl <= 0) {
1273
+ await this.#client.del(bucketKey);
1274
+ this.#markHealthy();
1275
+ return;
1276
+ }
1277
+ await this.#client.set(bucketKey, JSON.stringify(state), "EX", ttl);
1278
+ this.#markHealthy();
1279
+ } catch (error) {
1280
+ this.#onError("updateBucket", error);
1281
+ }
1282
+ }
1283
+ async getGlobalReset() {
1284
+ try {
1285
+ const resetAt = await this.#client.get(`${this.#prefix}global`);
1286
+ this.#markHealthy();
1287
+ return resetAt ? Number(resetAt) : 0;
1288
+ } catch (error) {
1289
+ this.#onError("getGlobalReset", error);
1290
+ return 0;
1291
+ }
1292
+ }
1293
+ async setGlobalReset(resetAt) {
1294
+ const globalKey = `${this.#prefix}global`;
1295
+ const ttl = Math.ceil((resetAt - Date.now()) / 1000);
1296
+ try {
1297
+ if (ttl <= 0) {
1298
+ await this.#client.del(globalKey);
1299
+ this.#markHealthy();
1300
+ return;
1301
+ }
1302
+ await this.#client.set(globalKey, String(resetAt), "EX", ttl);
1303
+ this.#markHealthy();
1304
+ } catch (error) {
1305
+ this.#onError("setGlobalReset", error);
1306
+ }
1307
+ }
1308
+ }
1009
1309
  // packages/rest/src/webhook.ts
1010
1310
  class WebhookClient {
1011
1311
  id;
@@ -1030,7 +1330,7 @@ class WebhookClient {
1030
1330
  const payload = typeof options === "string" ? { content: options } : options;
1031
1331
  const { thread_id, ...body } = payload;
1032
1332
  const query = thread_id ? `?thread_id=${thread_id}&wait=true` : `?wait=true`;
1033
- const formattedEmbeds = body.embeds?.map((e) => typeof e === "object" && e !== null && ("toJSON" in e) ? e.toJSON() : e);
1333
+ const formattedEmbeds = body.embeds?.map((e) => ("toJSON" in e) ? e.toJSON() : e);
1034
1334
  return this.#rest.post(`${Routes.webhook(this.id, this.token)}${query}`, {
1035
1335
  ...body,
1036
1336
  embeds: formattedEmbeds
@@ -1065,6 +1365,49 @@ class RESTError extends Error {
1065
1365
  var LIBRARY_VERSION = package_default.version;
1066
1366
  var LIBRARY_URL = "https://github.com/Ekretos/lunibee";
1067
1367
  var USER_AGENT = `DiscordBot (${LIBRARY_URL}, ${package_default.version})`;
1368
+ var REQUEST_DATA_KEYS = new Set([
1369
+ "body",
1370
+ "files",
1371
+ "query",
1372
+ "headers",
1373
+ "reason",
1374
+ "auth",
1375
+ "signal"
1376
+ ]);
1377
+ function isRequestData(value) {
1378
+ if (value === null || typeof value !== "object")
1379
+ return false;
1380
+ if (Array.isArray(value))
1381
+ return false;
1382
+ if (typeof FormData !== "undefined" && value instanceof FormData)
1383
+ return false;
1384
+ if (value instanceof Blob || value instanceof Uint8Array || value instanceof ArrayBuffer)
1385
+ return false;
1386
+ const keys = Object.keys(value);
1387
+ if (keys.length === 0)
1388
+ return false;
1389
+ return keys.every((key) => REQUEST_DATA_KEYS.has(key));
1390
+ }
1391
+ function serializeQuery(query) {
1392
+ if (query === undefined)
1393
+ return "";
1394
+ if (typeof query === "string")
1395
+ return query.length === 0 || query.startsWith("?") ? query : `?${query}`;
1396
+ const params = query instanceof URLSearchParams ? query : new URLSearchParams(Object.entries(query).flatMap(([key, value]) => value === undefined || value === null ? [] : [[key, String(value)]]));
1397
+ const serialized = params.toString();
1398
+ return serialized.length === 0 ? "" : `?${serialized}`;
1399
+ }
1400
+ function majorParameter(path) {
1401
+ const match = /^\/(channels|guilds|webhooks)\/(\d+)(?:\/([^/?]+))?/.exec(path);
1402
+ if (!match)
1403
+ return "@none";
1404
+ if (match[1] === "webhooks" && match[3] !== undefined)
1405
+ return `${match[2]}:${match[3]}`;
1406
+ return match[2];
1407
+ }
1408
+ function scopeBucket(hashOrRoute, major) {
1409
+ return `${hashOrRoute}|${major}`;
1410
+ }
1068
1411
  function createRetryPolicy(maxRetries = 2) {
1069
1412
  if (!Number.isFinite(maxRetries) || maxRetries < 0)
1070
1413
  throw new TypeError("maxRetries must be a non-negative finite number.");
@@ -1087,14 +1430,21 @@ class REST {
1087
1430
  #timeout;
1088
1431
  #retryPolicy;
1089
1432
  #token;
1090
- #globalResetAt = 0;
1091
- #buckets = new Map;
1092
- #routeBuckets = new Map;
1433
+ #store;
1434
+ #localQueues = new Map;
1435
+ #hooks = {};
1093
1436
  constructor(options = {}) {
1094
1437
  this.#token = options.token;
1095
1438
  this.#timeout = Math.max(1, options.timeout ?? 15000);
1096
1439
  this.#retryPolicy = options.retryPolicy ?? createRetryPolicy(options.retries ?? 2);
1097
1440
  this.#baseURL = (options.baseURL ?? "https://discord.com/api/v10").replace(/\/$/, "");
1441
+ this.#store = options.store ?? new MemoryRateLimitStore;
1442
+ if (options.hooks)
1443
+ this.#hooks = options.hooks;
1444
+ }
1445
+ setHooks(hooks) {
1446
+ this.#hooks = hooks;
1447
+ return this;
1098
1448
  }
1099
1449
  setToken(token) {
1100
1450
  if (!token.trim())
@@ -1107,56 +1457,91 @@ class REST {
1107
1457
  throw new TypeError("REST method is required.");
1108
1458
  if (!path.startsWith("/"))
1109
1459
  throw new TypeError("REST paths must start with '/'.");
1460
+ const files = options.files;
1461
+ if (files && files.length > 0 && !(body instanceof FormData))
1462
+ body = this.#fileForm(body, files);
1463
+ const query = serializeQuery(options.query);
1464
+ const finalPath = query ? `${path}${query}` : path;
1110
1465
  const route = `${normalizedMethod}:${this.#normalizeRoute(path)}`;
1111
- let bucketKey = this.#routeBuckets.get(route) ?? route;
1112
- let bucket = this.#buckets.get(bucketKey) ?? {
1113
- remaining: 1,
1114
- resetAt: 0,
1115
- queue: Promise.resolve()
1116
- };
1117
- this.#buckets.set(bucketKey, bucket);
1118
- const previous = bucket.queue;
1466
+ const major = majorParameter(path);
1467
+ let bucketKey = scopeBucket(await this.#store.getBucketHash(route) ?? route, major);
1468
+ const queueKey = bucketKey;
1469
+ const previous = this.#localQueues.get(queueKey) ?? Promise.resolve();
1119
1470
  let release;
1120
- bucket.queue = new Promise((resolve) => {
1471
+ const gate = new Promise((resolve) => {
1121
1472
  release = resolve;
1122
1473
  });
1474
+ this.#localQueues.set(queueKey, gate);
1123
1475
  await this.#abortable(previous, options.signal, path);
1124
1476
  try {
1125
1477
  for (let attempt = 0;attempt <= this.#retryPolicy.maxRetries; attempt++) {
1126
- await this.#wait(bucket, options.signal, path);
1478
+ await this.#wait(bucketKey, options.signal, path);
1127
1479
  await this.#waitGlobal(options.signal, path);
1128
1480
  const controller = new AbortController;
1129
1481
  const onAbort = () => controller.abort(options.signal?.reason);
1130
1482
  if (options.signal?.aborted)
1131
1483
  throw this.#abortError(path, options.signal.reason);
1132
- options.signal?.addEventListener("abort", onAbort, { once: true });
1484
+ options.signal?.addEventListener("abort", onAbort, {
1485
+ once: true
1486
+ });
1133
1487
  const timer = setTimeout(() => controller.abort(new DOMException("REST request timeout", "TimeoutError")), this.#timeout);
1134
1488
  const isFormData = typeof FormData !== "undefined" && body instanceof FormData;
1135
- const headers = {
1136
- ...this.#token ? { Authorization: `Bot ${this.#token}` } : {},
1137
- "User-Agent": USER_AGENT
1138
- };
1489
+ const headers = { ...options.headers };
1490
+ if (options.auth !== false && this.#token)
1491
+ headers["Authorization"] = `Bot ${this.#token}`;
1492
+ headers["User-Agent"] = USER_AGENT;
1493
+ if (options.reason !== undefined)
1494
+ headers["X-Audit-Log-Reason"] = encodeURIComponent(options.reason);
1139
1495
  if (!isFormData)
1140
1496
  headers["Content-Type"] = "application/json";
1141
1497
  const fetchBody = isFormData ? body : body === undefined ? undefined : JSON.stringify(body);
1142
1498
  try {
1143
- const response = await fetch(`${this.#baseURL}${path}`, {
1499
+ this.#emit(this.#hooks.onRequest, {
1500
+ method: normalizedMethod,
1501
+ path,
1502
+ attempt
1503
+ });
1504
+ const requestStart = Date.now();
1505
+ const response = await fetch(`${this.#baseURL}${finalPath}`, {
1144
1506
  method: normalizedMethod,
1145
1507
  headers,
1146
1508
  body: fetchBody,
1147
1509
  signal: controller.signal
1148
1510
  });
1149
- bucket = this.#update(response, bucket, route, bucketKey);
1150
- bucketKey = this.#routeBuckets.get(route) ?? bucketKey;
1511
+ this.#emit(this.#hooks.onResponse, {
1512
+ method: normalizedMethod,
1513
+ path,
1514
+ status: response.status,
1515
+ durationMs: Date.now() - requestStart
1516
+ });
1517
+ bucketKey = await this.#update(response, bucketKey, route, major);
1151
1518
  const payload = await this.#readPayload(response);
1152
1519
  if (response.ok)
1153
1520
  return response.status === 204 ? undefined : payload;
1154
1521
  const data = this.#errorData(payload);
1155
1522
  const retryAfter = response.status === 429 ? this.#retryAfter(response, data) : undefined;
1156
- if (data.global && retryAfter !== undefined)
1157
- this.#globalResetAt = Date.now() + retryAfter * 1000;
1523
+ if (data.global && retryAfter !== undefined) {
1524
+ const currentGlobal = await this.#store.getGlobalReset();
1525
+ await this.#store.setGlobalReset(Math.max(currentGlobal, Date.now() + retryAfter * 1000));
1526
+ }
1527
+ if (response.status === 429)
1528
+ this.#emit(this.#hooks.onRateLimit, {
1529
+ method: normalizedMethod,
1530
+ path,
1531
+ retryAfterMs: (retryAfter ?? 1) * 1000,
1532
+ global: data.global ?? false,
1533
+ bucket: await this.#store.getBucketHash(route)
1534
+ });
1158
1535
  if (attempt < this.#retryPolicy.maxRetries && this.#retryPolicy.shouldRetry(normalizedMethod, response.status)) {
1159
- await this.#sleep(this.#retryPolicy.getDelay(attempt, retryAfter), options.signal, path);
1536
+ const delay = this.#retryPolicy.getDelay(attempt, retryAfter);
1537
+ this.#emit(this.#hooks.onRetry, {
1538
+ method: normalizedMethod,
1539
+ path,
1540
+ attempt,
1541
+ status: response.status,
1542
+ delayMs: delay
1543
+ });
1544
+ await this.#sleep(delay, options.signal, path);
1160
1545
  continue;
1161
1546
  }
1162
1547
  throw new RESTError(data.message ?? response.statusText ?? `Discord REST request failed with status ${response.status}`, response.status, data.code, payload, { method: normalizedMethod, path });
@@ -1179,22 +1564,29 @@ class REST {
1179
1564
  throw new RESTError("Discord REST request exhausted its retry attempts", 0, undefined, undefined, { method: normalizedMethod, path });
1180
1565
  } finally {
1181
1566
  release();
1567
+ if (this.#localQueues.get(queueKey) === gate)
1568
+ this.#localQueues.delete(queueKey);
1182
1569
  }
1183
1570
  }
1571
+ #dispatch(method, path, bodyOrOptions, options) {
1572
+ if (options === undefined && isRequestData(bodyOrOptions))
1573
+ return this.request(method, path, bodyOrOptions.body, bodyOrOptions);
1574
+ return this.request(method, path, bodyOrOptions, options);
1575
+ }
1184
1576
  get(path, options) {
1185
- return this.request("GET", path, undefined, options);
1577
+ return this.request("GET", path, options?.body, options);
1186
1578
  }
1187
1579
  post(path, body, options) {
1188
- return this.request("POST", path, body, options);
1580
+ return this.#dispatch("POST", path, body, options);
1189
1581
  }
1190
1582
  patch(path, body, options) {
1191
- return this.request("PATCH", path, body, options);
1583
+ return this.#dispatch("PATCH", path, body, options);
1192
1584
  }
1193
1585
  put(path, body, options) {
1194
- return this.request("PUT", path, body, options);
1586
+ return this.#dispatch("PUT", path, body, options);
1195
1587
  }
1196
1588
  delete(path, options) {
1197
- return this.request("DELETE", path, undefined, options);
1589
+ return this.request("DELETE", path, options?.body, options);
1198
1590
  }
1199
1591
  #fileForm(payload, files) {
1200
1592
  const form = new FormData;
@@ -1214,13 +1606,22 @@ class REST {
1214
1606
  patchWithFiles(path, payload, files, options) {
1215
1607
  return this.request("PATCH", path, this.#fileForm(payload, files), options);
1216
1608
  }
1217
- async#wait(bucket, signal, path) {
1609
+ #emit(hook, ctx) {
1610
+ if (!hook)
1611
+ return;
1612
+ Promise.resolve().then(() => hook(ctx)).catch(() => {});
1613
+ }
1614
+ async#wait(bucketKey, signal, path) {
1615
+ const bucket = await this.#store.getBucket(bucketKey);
1616
+ if (!bucket)
1617
+ return;
1218
1618
  const delay = bucket.resetAt - Date.now();
1219
1619
  if (bucket.remaining <= 0 && delay > 0)
1220
1620
  await this.#sleep(delay, signal, path);
1221
1621
  }
1222
1622
  async#waitGlobal(signal, path) {
1223
- const delay = this.#globalResetAt - Date.now();
1623
+ const globalResetAt = await this.#store.getGlobalReset();
1624
+ const delay = globalResetAt - Date.now();
1224
1625
  if (delay > 0)
1225
1626
  await this.#sleep(delay, signal, path);
1226
1627
  }
@@ -1284,16 +1685,17 @@ class REST {
1284
1685
  const routePath = queryIndex === -1 ? path : path.slice(0, queryIndex);
1285
1686
  return routePath.replace(/\/\d+(?=\/|$)/g, "/:id");
1286
1687
  }
1287
- #update(response, bucket, route, bucketKey) {
1688
+ async#update(response, bucketKey, route, major) {
1689
+ let currentKey = bucketKey;
1288
1690
  const serverBucket = response.headers.get("X-RateLimit-Bucket");
1289
1691
  if (serverBucket) {
1290
- this.#routeBuckets.set(route, serverBucket);
1291
- if (serverBucket !== bucketKey) {
1292
- const shared = this.#buckets.get(serverBucket) ?? bucket;
1293
- this.#buckets.set(serverBucket, shared);
1294
- bucket = shared;
1295
- }
1692
+ await this.#store.setBucketHash(route, serverBucket);
1693
+ currentKey = scopeBucket(serverBucket, major);
1296
1694
  }
1695
+ let bucket = await this.#store.getBucket(currentKey) ?? {
1696
+ remaining: 1,
1697
+ resetAt: 0
1698
+ };
1297
1699
  const remaining = Number(response.headers.get("X-RateLimit-Remaining"));
1298
1700
  const resetAfter = Number(response.headers.get("X-RateLimit-Reset-After"));
1299
1701
  const reset = Number(response.headers.get("X-RateLimit-Reset"));
@@ -1308,12 +1710,15 @@ class REST {
1308
1710
  if (Number.isFinite(retryAfter))
1309
1711
  bucket.resetAt = Math.max(bucket.resetAt, Date.now() + retryAfter * 1000);
1310
1712
  }
1713
+ await this.#store.updateBucket(currentKey, bucket);
1311
1714
  if (response.headers.get("X-RateLimit-Global") === "true") {
1312
1715
  const retryAfter = Number(response.headers.get("Retry-After"));
1313
- if (Number.isFinite(retryAfter))
1314
- this.#globalResetAt = Math.max(this.#globalResetAt, Date.now() + retryAfter * 1000);
1716
+ if (Number.isFinite(retryAfter)) {
1717
+ const currentGlobal = await this.#store.getGlobalReset();
1718
+ await this.#store.setGlobalReset(Math.max(currentGlobal, Date.now() + retryAfter * 1000));
1719
+ }
1315
1720
  }
1316
- return bucket;
1721
+ return currentKey;
1317
1722
  }
1318
1723
  }
1319
1724
 
@@ -1459,6 +1864,13 @@ class Guild extends BaseStructure {
1459
1864
  vanityUrlCode;
1460
1865
  nsfwLevel;
1461
1866
  discoverySplash;
1867
+ rulesChannelId;
1868
+ systemChannelId;
1869
+ systemChannelFlags;
1870
+ maxMembers;
1871
+ mfaLevel;
1872
+ explicitContentFilter;
1873
+ defaultMessageNotifications;
1462
1874
  constructor(data) {
1463
1875
  super(data.id);
1464
1876
  if (!data.name)
@@ -1480,6 +1892,14 @@ class Guild extends BaseStructure {
1480
1892
  this.vanityUrlCode = data.vanity_url_code ?? null;
1481
1893
  this.nsfwLevel = data.nsfw_level ?? 0;
1482
1894
  this.discoverySplash = data.discovery_splash ?? null;
1895
+ const d = data;
1896
+ this.rulesChannelId = d.rules_channel_id ?? null;
1897
+ this.systemChannelId = d.system_channel_id ?? null;
1898
+ this.systemChannelFlags = d.system_channel_flags ?? 0;
1899
+ this.maxMembers = d.max_members ?? 0;
1900
+ this.mfaLevel = d.mfa_level ?? 0;
1901
+ this.explicitContentFilter = d.explicit_content_filter ?? 0;
1902
+ this.defaultMessageNotifications = d.default_message_notifications ?? 0;
1483
1903
  }
1484
1904
  iconURL(options = {}) {
1485
1905
  if (!this.icon)
@@ -1501,12 +1921,27 @@ class Guild extends BaseStructure {
1501
1921
  return null;
1502
1922
  return cdnURL(`/discovery-splashes/${this.id}`, this.discoverySplash, options);
1503
1923
  }
1924
+ widgetImageURL(style = "shield") {
1925
+ return `https://discord.com/api/guilds/${this.id}/widget.png?style=${style}`;
1926
+ }
1504
1927
  hasFeature(feature) {
1505
1928
  return this.features.includes(feature);
1506
1929
  }
1507
1930
  get isCommunity() {
1508
1931
  return this.hasFeature("COMMUNITY");
1509
1932
  }
1933
+ get isPartnered() {
1934
+ return this.hasFeature("PARTNERED");
1935
+ }
1936
+ get isVerified() {
1937
+ return this.hasFeature("VERIFIED");
1938
+ }
1939
+ get isBoosted() {
1940
+ return this.premiumSubscriptionCount > 0;
1941
+ }
1942
+ get boostLevel() {
1943
+ return this.premiumTier;
1944
+ }
1510
1945
  get hasVanityUrl() {
1511
1946
  return this.vanityUrlCode !== null;
1512
1947
  }
@@ -1517,141 +1952,14 @@ class Guild extends BaseStructure {
1517
1952
  return this.name;
1518
1953
  }
1519
1954
  }
1520
- // packages/structures/src/permissions.ts
1521
- var Permissions2 = {
1522
- CreateInstantInvite: 1n << 0n,
1523
- KickMembers: 1n << 1n,
1524
- BanMembers: 1n << 2n,
1525
- Administrator: 1n << 3n,
1526
- ManageChannels: 1n << 4n,
1527
- ManageGuild: 1n << 5n,
1528
- AddReactions: 1n << 6n,
1529
- ViewAuditLog: 1n << 7n,
1530
- PrioritySpeaker: 1n << 8n,
1531
- Stream: 1n << 9n,
1532
- ViewChannel: 1n << 10n,
1533
- SendMessages: 1n << 11n,
1534
- SendTTSMessages: 1n << 12n,
1535
- ManageMessages: 1n << 13n,
1536
- EmbedLinks: 1n << 14n,
1537
- AttachFiles: 1n << 15n,
1538
- ReadMessageHistory: 1n << 16n,
1539
- MentionEveryone: 1n << 17n,
1540
- UseExternalEmojis: 1n << 18n,
1541
- ViewGuildInsights: 1n << 19n,
1542
- Connect: 1n << 20n,
1543
- Speak: 1n << 21n,
1544
- MuteMembers: 1n << 22n,
1545
- DeafenMembers: 1n << 23n,
1546
- MoveMembers: 1n << 24n,
1547
- UseVAD: 1n << 25n,
1548
- ChangeNickname: 1n << 26n,
1549
- ManageNicknames: 1n << 27n,
1550
- ManageRoles: 1n << 28n,
1551
- ManageWebhooks: 1n << 29n,
1552
- ManageGuildExpressions: 1n << 30n,
1553
- UseApplicationCommands: 1n << 31n,
1554
- RequestToSpeak: 1n << 32n,
1555
- ManageEvents: 1n << 33n,
1556
- ManageThreads: 1n << 34n,
1557
- CreatePublicThreads: 1n << 35n,
1558
- CreatePrivateThreads: 1n << 36n,
1559
- UseExternalStickers: 1n << 37n,
1560
- SendMessagesInThreads: 1n << 38n,
1561
- UseEmbeddedActivities: 1n << 39n,
1562
- ModerateMembers: 1n << 40n,
1563
- ViewCreatorMonetizationAnalytics: 1n << 41n,
1564
- UseSoundboard: 1n << 42n,
1565
- CreateGuildExpressions: 1n << 43n,
1566
- CreateEvents: 1n << 44n,
1567
- UseExternalSounds: 1n << 45n,
1568
- SendVoiceMessages: 1n << 46n,
1569
- SendPolls: 1n << 49n,
1570
- UseExternalApps: 1n << 50n
1571
- };
1572
-
1573
- class PermissionSet2 {
1574
- bitfield;
1575
- constructor(value = 0n) {
1576
- try {
1577
- if (Array.isArray(value)) {
1578
- let bit = 0n;
1579
- for (const item of value)
1580
- bit |= this.#resolve(item);
1581
- this.bitfield = bit;
1582
- } else if (value instanceof PermissionSet2) {
1583
- this.bitfield = value.bitfield;
1584
- } else {
1585
- const bitfield = this.#resolve(value);
1586
- if (bitfield < 0n)
1587
- throw new RangeError("Permission bitfield cannot be negative.");
1588
- this.bitfield = bitfield;
1589
- }
1590
- } catch (error) {
1591
- if (error instanceof RangeError)
1592
- throw error;
1593
- throw new TypeError("Permission bitfield must be a valid non-negative integer.", { cause: error });
1594
- }
1595
- }
1596
- has(...permissions) {
1597
- return permissions.every((permission) => (this.bitfield & this.#resolve(permission)) === this.#resolve(permission));
1598
- }
1599
- any(...permissions) {
1600
- return permissions.some((permission) => (this.bitfield & this.#resolve(permission)) !== 0n);
1601
- }
1602
- add(...permissions) {
1603
- let bitfield = this.bitfield;
1604
- for (const permission of permissions)
1605
- bitfield |= this.#resolve(permission);
1606
- return new PermissionSet2(bitfield);
1607
- }
1608
- remove(...permissions) {
1609
- let bitfield = this.bitfield;
1610
- for (const permission of permissions)
1611
- bitfield &= ~this.#resolve(permission);
1612
- return new PermissionSet2(bitfield);
1613
- }
1614
- equals(other) {
1615
- return this.bitfield === (other instanceof PermissionSet2 ? other.bitfield : new PermissionSet2(other).bitfield);
1616
- }
1617
- toString() {
1618
- return this.bitfield.toString();
1619
- }
1620
- toArray() {
1621
- return Object.keys(Permissions2).filter((permission) => this.has(permission));
1622
- }
1623
- #resolve(permission) {
1624
- if (permission instanceof PermissionSet2)
1625
- return permission.bitfield;
1626
- if (typeof permission === "bigint")
1627
- return permission;
1628
- if (typeof permission === "number")
1629
- return BigInt(permission);
1630
- if (Array.isArray(permission)) {
1631
- let bit = 0n;
1632
- for (const p of permission)
1633
- bit |= this.#resolve(p);
1634
- return bit;
1635
- }
1636
- if (typeof permission === "string") {
1637
- if (permission in Permissions2)
1638
- return Permissions2[permission];
1639
- const matchedKey = Object.keys(Permissions2).find((k) => k.toLowerCase() === permission.toLowerCase());
1640
- if (matchedKey)
1641
- return Permissions2[matchedKey];
1642
- return BigInt(permission);
1643
- }
1644
- return 0n;
1645
- }
1646
- }
1647
-
1648
- class PermissionsBitField2 extends PermissionSet2 {
1649
- constructor(value = 0n) {
1650
- super(value);
1651
- }
1955
+ // packages/structures/src/resources.ts
1956
+ function toDateOrNull(value) {
1957
+ if (!value)
1958
+ return null;
1959
+ const date = new Date(value);
1960
+ return Number.isNaN(date.getTime()) ? null : date;
1652
1961
  }
1653
1962
 
1654
- // packages/structures/src/resources.ts
1655
1963
  class GuildMember {
1656
1964
  user;
1657
1965
  guildId;
@@ -1660,6 +1968,10 @@ class GuildMember {
1660
1968
  pending;
1661
1969
  joinedAt;
1662
1970
  permissions;
1971
+ avatarHash;
1972
+ premiumSince;
1973
+ timedOutUntil;
1974
+ flags;
1663
1975
  constructor(data) {
1664
1976
  this.user = new User(data.user);
1665
1977
  if (!/^\d{1,20}$/.test(data.guild_id))
@@ -1671,11 +1983,26 @@ class GuildMember {
1671
1983
  this.joinedAt = data.joined_at ? new Date(data.joined_at) : undefined;
1672
1984
  if (this.joinedAt?.toString() === "Invalid Date")
1673
1985
  throw new RangeError("Member joined_at must be a valid date.");
1674
- this.permissions = new PermissionsBitField2(data.permissions ?? 0n);
1986
+ this.permissions = new PermissionsBitField(data.permissions ?? 0n);
1987
+ this.avatarHash = data.avatar ?? null;
1988
+ this.premiumSince = toDateOrNull(data.premium_since);
1989
+ this.timedOutUntil = toDateOrNull(data.communication_disabled_until);
1990
+ this.flags = data.flags ?? 0;
1675
1991
  }
1676
1992
  get displayName() {
1677
1993
  return this.nickname ?? this.user.displayName;
1678
1994
  }
1995
+ get isTimedOut() {
1996
+ return this.timedOutUntil !== null && this.timedOutUntil > new Date;
1997
+ }
1998
+ avatarURL(options = {}) {
1999
+ if (this.avatarHash)
2000
+ return cdnURL(`/guilds/${this.guildId}/users/${this.user.id}/avatars`, this.avatarHash, options);
2001
+ return this.user.avatarURL(options);
2002
+ }
2003
+ displayAvatarURL(options = {}) {
2004
+ return this.avatarURL(options) ?? this.user.displayAvatarURL(options);
2005
+ }
1679
2006
  toString() {
1680
2007
  return this.user.toString();
1681
2008
  }
@@ -1688,6 +2015,10 @@ class Role extends BaseStructure {
1688
2015
  permissions;
1689
2016
  managed;
1690
2017
  mentionable;
2018
+ position;
2019
+ unicodeEmoji;
2020
+ iconHash;
2021
+ tags;
1691
2022
  constructor(data) {
1692
2023
  super(data.id);
1693
2024
  if (!data.name)
@@ -1695,9 +2026,24 @@ class Role extends BaseStructure {
1695
2026
  this.name = data.name;
1696
2027
  this.color = data.color ?? 0;
1697
2028
  this.hoist = data.hoist ?? false;
1698
- this.permissions = new PermissionsBitField2(data.permissions ?? 0n);
2029
+ this.permissions = new PermissionsBitField(data.permissions ?? 0n);
1699
2030
  this.managed = data.managed ?? false;
1700
2031
  this.mentionable = data.mentionable ?? false;
2032
+ this.position = data.position ?? 0;
2033
+ this.unicodeEmoji = data.unicode_emoji ?? null;
2034
+ this.iconHash = data.icon ?? null;
2035
+ this.tags = data.tags ?? null;
2036
+ }
2037
+ get colorHex() {
2038
+ return `#${this.color.toString(16).padStart(6, "0").toUpperCase()}`;
2039
+ }
2040
+ iconURL(options = {}) {
2041
+ if (!this.iconHash)
2042
+ return null;
2043
+ return cdnURL(`/role-icons/${this.id}`, this.iconHash, options);
2044
+ }
2045
+ isEveryone(guildId) {
2046
+ return this.id === guildId;
1701
2047
  }
1702
2048
  toString() {
1703
2049
  return `<@&${this.id}>`;
@@ -1712,6 +2058,218 @@ class TextChannel extends Channel {
1712
2058
  return `<#${this.id}>`;
1713
2059
  }
1714
2060
  }
2061
+
2062
+ class Invite {
2063
+ code;
2064
+ guildId;
2065
+ channelId;
2066
+ inviter;
2067
+ uses;
2068
+ maxUses;
2069
+ maxAge;
2070
+ temporary;
2071
+ createdAt;
2072
+ expiresAt;
2073
+ constructor(data) {
2074
+ if (!data.code)
2075
+ throw new TypeError("An invite requires a code.");
2076
+ this.code = data.code;
2077
+ this.guildId = data.guild?.id ?? null;
2078
+ this.channelId = data.channel?.id ?? null;
2079
+ this.inviter = data.inviter ? new User(data.inviter) : null;
2080
+ this.uses = data.uses ?? 0;
2081
+ this.maxUses = data.max_uses ?? 0;
2082
+ this.maxAge = data.max_age ?? 0;
2083
+ this.temporary = data.temporary ?? false;
2084
+ this.createdAt = data.created_at ? new Date(data.created_at) : null;
2085
+ this.expiresAt = data.expires_at ? new Date(data.expires_at) : null;
2086
+ }
2087
+ get url() {
2088
+ return `https://discord.gg/${this.code}`;
2089
+ }
2090
+ toString() {
2091
+ return this.url;
2092
+ }
2093
+ }
2094
+ var WebhookType = {
2095
+ Incoming: 1,
2096
+ ChannelFollower: 2,
2097
+ Application: 3
2098
+ };
2099
+
2100
+ class Webhook extends BaseStructure {
2101
+ type;
2102
+ name;
2103
+ avatarHash;
2104
+ channelId;
2105
+ guildId;
2106
+ applicationId;
2107
+ token;
2108
+ constructor(data) {
2109
+ super(data.id);
2110
+ this.type = data.type ?? WebhookType.Incoming;
2111
+ this.name = data.name ?? null;
2112
+ this.avatarHash = data.avatar ?? null;
2113
+ this.channelId = data.channel_id ?? null;
2114
+ this.guildId = data.guild_id ?? null;
2115
+ this.applicationId = data.application_id ?? null;
2116
+ this.token = data.token ?? null;
2117
+ }
2118
+ avatarURL(options = {}) {
2119
+ if (!this.avatarHash)
2120
+ return null;
2121
+ return cdnURL(`/avatars/${this.id}`, this.avatarHash, options);
2122
+ }
2123
+ get url() {
2124
+ return this.token ? `https://discord.com/api/webhooks/${this.id}/${this.token}` : null;
2125
+ }
2126
+ toString() {
2127
+ return this.url ?? this.id;
2128
+ }
2129
+ }
2130
+
2131
+ class Emoji extends BaseStructure {
2132
+ name;
2133
+ roleIds;
2134
+ user;
2135
+ requireColons;
2136
+ managed;
2137
+ animated;
2138
+ available;
2139
+ constructor(data) {
2140
+ super(data.id ?? "unicode");
2141
+ this.name = data.name;
2142
+ this.roleIds = data.roles ?? [];
2143
+ this.user = data.user ? new User(data.user) : null;
2144
+ this.requireColons = data.require_colons ?? false;
2145
+ this.managed = data.managed ?? false;
2146
+ this.animated = data.animated ?? false;
2147
+ this.available = data.available ?? true;
2148
+ }
2149
+ url(options = {}) {
2150
+ if (!this.id || this.id === "unicode")
2151
+ return null;
2152
+ const ext = options.extension ?? (this.animated ? "gif" : "png");
2153
+ const size = options.size ? `?size=${options.size}` : "";
2154
+ return `${CDN_BASE}/emojis/${this.id}.${ext}${size}`;
2155
+ }
2156
+ toString() {
2157
+ return this.id !== "unicode" ? `<${this.animated ? "a" : ""}:${this.name}:${this.id}>` : this.name ?? "";
2158
+ }
2159
+ }
2160
+
2161
+ class AutoModerationRule extends BaseStructure {
2162
+ guildId;
2163
+ name;
2164
+ creatorId;
2165
+ eventType;
2166
+ triggerType;
2167
+ triggerMetadata;
2168
+ actions;
2169
+ enabled;
2170
+ exemptRoles;
2171
+ exemptChannels;
2172
+ constructor(data) {
2173
+ super(data.id);
2174
+ if (!/^\d{1,20}$/.test(data.guild_id))
2175
+ throw new TypeError("AutoModerationRule guild_id must be a valid snowflake.");
2176
+ this.guildId = data.guild_id;
2177
+ this.name = data.name;
2178
+ this.creatorId = data.creator_id;
2179
+ this.eventType = data.event_type;
2180
+ this.triggerType = data.trigger_type;
2181
+ this.triggerMetadata = data.trigger_metadata;
2182
+ this.actions = data.actions;
2183
+ this.enabled = data.enabled;
2184
+ this.exemptRoles = data.exempt_roles;
2185
+ this.exemptChannels = data.exempt_channels;
2186
+ }
2187
+ toJSON() {
2188
+ return {
2189
+ id: this.id,
2190
+ guildId: this.guildId,
2191
+ name: this.name,
2192
+ creatorId: this.creatorId,
2193
+ eventType: this.eventType,
2194
+ triggerType: this.triggerType,
2195
+ triggerMetadata: this.triggerMetadata,
2196
+ actions: this.actions,
2197
+ enabled: this.enabled,
2198
+ exemptRoles: this.exemptRoles,
2199
+ exemptChannels: this.exemptChannels
2200
+ };
2201
+ }
2202
+ }
2203
+
2204
+ class WelcomeScreenChannel {
2205
+ channelId;
2206
+ description;
2207
+ emojiId;
2208
+ emojiName;
2209
+ constructor(data) {
2210
+ this.channelId = data.channel_id;
2211
+ this.description = data.description;
2212
+ this.emojiId = data.emoji_id;
2213
+ this.emojiName = data.emoji_name;
2214
+ }
2215
+ }
2216
+
2217
+ class GuildWelcomeScreen {
2218
+ description;
2219
+ channels;
2220
+ constructor(data) {
2221
+ this.description = data.description;
2222
+ this.channels = data.welcome_channels.map((c) => new WelcomeScreenChannel(c));
2223
+ }
2224
+ }
2225
+
2226
+ class OnboardingPromptOption extends BaseStructure {
2227
+ channelIds;
2228
+ roleIds;
2229
+ emoji;
2230
+ title;
2231
+ description;
2232
+ constructor(data) {
2233
+ super(data.id);
2234
+ this.channelIds = data.channel_ids;
2235
+ this.roleIds = data.role_ids;
2236
+ this.emoji = data.emoji;
2237
+ this.title = data.title;
2238
+ this.description = data.description;
2239
+ }
2240
+ }
2241
+
2242
+ class OnboardingPrompt extends BaseStructure {
2243
+ type;
2244
+ options;
2245
+ title;
2246
+ singleSelect;
2247
+ required;
2248
+ inOnboarding;
2249
+ constructor(data) {
2250
+ super(data.id);
2251
+ this.type = data.type;
2252
+ this.options = data.options.map((o) => new OnboardingPromptOption(o));
2253
+ this.title = data.title;
2254
+ this.singleSelect = data.single_select;
2255
+ this.required = data.required;
2256
+ this.inOnboarding = data.in_onboarding;
2257
+ }
2258
+ }
2259
+
2260
+ class GuildOnboarding extends BaseStructure {
2261
+ prompts;
2262
+ defaultChannelIds;
2263
+ enabled;
2264
+ mode;
2265
+ constructor(data) {
2266
+ super(data.guild_id);
2267
+ this.prompts = data.prompts.map((p) => new OnboardingPrompt(p));
2268
+ this.defaultChannelIds = data.default_channel_ids;
2269
+ this.enabled = data.enabled;
2270
+ this.mode = data.mode;
2271
+ }
2272
+ }
1715
2273
  // packages/structures/src/interactions.ts
1716
2274
  var InteractionType = {
1717
2275
  Ping: 1,
@@ -2002,8 +2560,7 @@ class CommandInteraction extends Interaction {
2002
2560
  super(client, data);
2003
2561
  const rawOptions = data.data?.options ?? [];
2004
2562
  const resolved = data.data?.resolved ?? {};
2005
- const sub = rawOptions.find((o) => o.type === 1 || o.type === 2);
2006
- this.options = new CommandOptions(sub?.options ?? rawOptions, resolved);
2563
+ this.options = new CommandOptions(rawOptions, resolved);
2007
2564
  }
2008
2565
  }
2009
2566
 
@@ -2233,8 +2790,38 @@ class Embed {
2233
2790
  return new Embed(data);
2234
2791
  }
2235
2792
  }
2793
+ // packages/structures/src/audit-log.ts
2794
+ class AuditLogEntry extends BaseStructure {
2795
+ targetId;
2796
+ userId;
2797
+ actionType;
2798
+ changes;
2799
+ options;
2800
+ reason;
2801
+ constructor(data) {
2802
+ super(data.id);
2803
+ this.targetId = data.target_id;
2804
+ this.userId = data.user_id;
2805
+ this.actionType = data.action_type;
2806
+ this.changes = data.changes ?? [];
2807
+ this.options = data.options ?? null;
2808
+ this.reason = data.reason ?? null;
2809
+ }
2810
+ }
2811
+
2812
+ class AuditLog {
2813
+ entries;
2814
+ constructor(data) {
2815
+ this.entries = new Map;
2816
+ for (const entryData of data.audit_log_entries) {
2817
+ this.entries.set(entryData.id, new AuditLogEntry(entryData));
2818
+ }
2819
+ }
2820
+ }
2236
2821
 
2237
2822
  // packages/structures/src/index.ts
2823
+ var NON_SYSTEM_MESSAGE_TYPES = new Set([0, 19, 20, 23]);
2824
+
2238
2825
  class Message extends BaseStructure {
2239
2826
  content;
2240
2827
  author;
@@ -2280,6 +2867,12 @@ class Message extends BaseStructure {
2280
2867
  get embedsSuppressed() {
2281
2868
  return (this.flags & 4) !== 0;
2282
2869
  }
2870
+ get createdTimestamp() {
2871
+ return this.timestamp.getTime();
2872
+ }
2873
+ get createdAt() {
2874
+ return this.timestamp;
2875
+ }
2283
2876
  edit(options) {
2284
2877
  if (!this.#context)
2285
2878
  throw new Error("This message is not attached to a client.");
@@ -2334,6 +2927,51 @@ class Message extends BaseStructure {
2334
2927
  throw new Error("This message is not attached to a client.");
2335
2928
  return this.#context.unpinMessage(this.channelId, this.id);
2336
2929
  }
2930
+ get isEphemeral() {
2931
+ return (this.flags & 64) !== 0;
2932
+ }
2933
+ get isPinned() {
2934
+ return this.pinned;
2935
+ }
2936
+ get isSystemMessage() {
2937
+ return !NON_SYSTEM_MESSAGE_TYPES.has(this.type);
2938
+ }
2939
+ get isCrosspost() {
2940
+ return (this.flags & 2) !== 0;
2941
+ }
2942
+ get hasAttachments() {
2943
+ return this.attachments.length > 0;
2944
+ }
2945
+ get hasEmbeds() {
2946
+ return this.embeds.length > 0;
2947
+ }
2948
+ get hasComponents() {
2949
+ return this.components.length > 0;
2950
+ }
2951
+ suppressEmbeds() {
2952
+ return this.edit({ flags: this.flags | 4 });
2953
+ }
2954
+ toJSON() {
2955
+ return {
2956
+ id: this.id,
2957
+ content: this.content,
2958
+ channelId: this.channelId,
2959
+ guildId: this.guildId,
2960
+ flags: this.flags,
2961
+ pinned: this.pinned,
2962
+ mentionEveryone: this.mentionEveryone,
2963
+ type: this.type,
2964
+ timestamp: this.timestamp.toISOString(),
2965
+ author: { id: this.author.id, username: this.author.username },
2966
+ attachments: [...this.attachments],
2967
+ embeds: [...this.embeds],
2968
+ components: [...this.components],
2969
+ mentions: this.mentions.map((u) => u.id),
2970
+ mentionRoles: [...this.mentionRoles],
2971
+ reference: this.reference,
2972
+ referencedMessage: this.referencedMessage ? this.referencedMessage.id : this.referencedMessage
2973
+ };
2974
+ }
2337
2975
  }
2338
2976
 
2339
2977
  // packages/managers/src/message.ts
@@ -2425,6 +3063,11 @@ class UserManager extends ResourceManager {
2425
3063
  }
2426
3064
  }
2427
3065
  // packages/managers/src/guild.ts
3066
+ function withQuery(path, params) {
3067
+ const suffix = params.toString();
3068
+ return suffix ? `${path}?${suffix}` : path;
3069
+ }
3070
+
2428
3071
  class GuildManager extends ResourceManager {
2429
3072
  #rest;
2430
3073
  constructor(rest) {
@@ -2454,7 +3097,101 @@ class GuildManager extends ResourceManager {
2454
3097
  async fetchInvites(id) {
2455
3098
  return this.#rest.get(Routes.guildInvites(id));
2456
3099
  }
3100
+ async fetchAuditLog(guildId, options = {}) {
3101
+ const params = new URLSearchParams;
3102
+ if (options.userId)
3103
+ params.set("user_id", options.userId);
3104
+ if (options.actionType !== undefined)
3105
+ params.set("action_type", String(options.actionType));
3106
+ if (options.before)
3107
+ params.set("before", options.before);
3108
+ if (options.after)
3109
+ params.set("after", options.after);
3110
+ if (options.limit !== undefined)
3111
+ params.set("limit", String(Math.min(100, Math.max(1, options.limit))));
3112
+ return this.#rest.get(withQuery(Routes.guildAuditLog(guildId), params));
3113
+ }
3114
+ async fetchMembers(guildId, options = {}) {
3115
+ const params = new URLSearchParams;
3116
+ if (options.limit !== undefined)
3117
+ params.set("limit", String(Math.min(1000, Math.max(1, options.limit))));
3118
+ if (options.after)
3119
+ params.set("after", options.after);
3120
+ return this.#rest.get(withQuery(Routes.guildMembers(guildId), params));
3121
+ }
3122
+ async fetchAutoModerationRules(guildId) {
3123
+ const rules = await this.#rest.get(Routes.guildAutoModerationRules(guildId));
3124
+ return rules.map((r) => new AutoModerationRule(r));
3125
+ }
3126
+ async fetchAutoModerationRule(guildId, ruleId) {
3127
+ const rule = await this.#rest.get(Routes.guildAutoModerationRule(guildId, ruleId));
3128
+ return new AutoModerationRule(rule);
3129
+ }
3130
+ async createAutoModerationRule(guildId, options) {
3131
+ const rule = await this.#rest.post(Routes.guildAutoModerationRules(guildId), options);
3132
+ return new AutoModerationRule(rule);
3133
+ }
3134
+ async editAutoModerationRule(guildId, ruleId, options) {
3135
+ const rule = await this.#rest.patch(Routes.guildAutoModerationRule(guildId, ruleId), options);
3136
+ return new AutoModerationRule(rule);
3137
+ }
3138
+ async deleteAutoModerationRule(guildId, ruleId) {
3139
+ await this.#rest.delete(Routes.guildAutoModerationRule(guildId, ruleId));
3140
+ }
2457
3141
  }
3142
+ var AuditLogEvent = {
3143
+ GuildUpdate: 1,
3144
+ ChannelCreate: 10,
3145
+ ChannelUpdate: 11,
3146
+ ChannelDelete: 12,
3147
+ ChannelOverwriteCreate: 13,
3148
+ ChannelOverwriteUpdate: 14,
3149
+ ChannelOverwriteDelete: 15,
3150
+ MemberKick: 20,
3151
+ MemberPrune: 21,
3152
+ MemberBanAdd: 22,
3153
+ MemberBanRemove: 23,
3154
+ MemberUpdate: 24,
3155
+ MemberRoleUpdate: 25,
3156
+ MemberMove: 26,
3157
+ MemberDisconnect: 27,
3158
+ BotAdd: 28,
3159
+ RoleCreate: 30,
3160
+ RoleUpdate: 31,
3161
+ RoleDelete: 32,
3162
+ InviteCreate: 40,
3163
+ InviteUpdate: 41,
3164
+ InviteDelete: 42,
3165
+ WebhookCreate: 50,
3166
+ WebhookUpdate: 51,
3167
+ WebhookDelete: 52,
3168
+ EmojiCreate: 60,
3169
+ EmojiUpdate: 61,
3170
+ EmojiDelete: 62,
3171
+ MessageDelete: 72,
3172
+ MessageBulkDelete: 73,
3173
+ MessagePin: 74,
3174
+ MessageUnpin: 75,
3175
+ IntegrationCreate: 80,
3176
+ IntegrationUpdate: 81,
3177
+ IntegrationDelete: 82,
3178
+ StageInstanceCreate: 83,
3179
+ StageInstanceUpdate: 84,
3180
+ StageInstanceDelete: 85,
3181
+ StickerCreate: 90,
3182
+ StickerUpdate: 91,
3183
+ StickerDelete: 92,
3184
+ ScheduledEventCreate: 100,
3185
+ ScheduledEventUpdate: 101,
3186
+ ScheduledEventDelete: 102,
3187
+ ThreadCreate: 110,
3188
+ ThreadUpdate: 111,
3189
+ ThreadDelete: 112,
3190
+ AutoModerationRuleCreate: 140,
3191
+ AutoModerationRuleUpdate: 141,
3192
+ AutoModerationRuleDelete: 142,
3193
+ AutoModerationBlockMessage: 143
3194
+ };
2458
3195
  // packages/managers/src/role.ts
2459
3196
  class RoleManager extends ResourceManager {
2460
3197
  #rest;
@@ -2575,6 +3312,44 @@ class ApplicationCommandManager {
2575
3312
  await this.#rest.delete(Routes.guildApplicationCommand(this.#applicationId, guildId, commandId));
2576
3313
  }
2577
3314
  }
3315
+ // packages/managers/src/emoji.ts
3316
+ class EmojiManager extends Manager {
3317
+ #rest;
3318
+ #guildId;
3319
+ constructor(rest, guildId) {
3320
+ super();
3321
+ this.#rest = rest;
3322
+ this.#guildId = guildId;
3323
+ }
3324
+ async fetch(emojiId) {
3325
+ return this.upsert(await this.#rest.get(Routes.guildEmoji(this.#guildId, emojiId)));
3326
+ }
3327
+ async fetchAll() {
3328
+ const data = await this.#rest.get(Routes.guildEmoji(this.#guildId));
3329
+ return data.map((item) => this.upsert(item));
3330
+ }
3331
+ async create(options) {
3332
+ return this.upsert(await this.#rest.post(Routes.guildEmoji(this.#guildId), options));
3333
+ }
3334
+ async edit(emojiId, options) {
3335
+ return this.upsert(await this.#rest.patch(Routes.guildEmoji(this.#guildId, emojiId), options));
3336
+ }
3337
+ async deleteEmoji(emojiId) {
3338
+ await this.#rest.delete(Routes.guildEmoji(this.#guildId, emojiId));
3339
+ this.delete(emojiId);
3340
+ }
3341
+ upsert(data) {
3342
+ const key = data.id != null ? data.id : `unicode:${data.name ?? ""}`;
3343
+ const existing = this.get(key);
3344
+ const emoji = new Emoji(data);
3345
+ if (existing) {
3346
+ Object.assign(existing, emoji);
3347
+ return existing;
3348
+ }
3349
+ this.set(key, emoji);
3350
+ return emoji;
3351
+ }
3352
+ }
2578
3353
 
2579
3354
  // packages/managers/src/index.ts
2580
3355
  class ChannelManager extends Manager {
@@ -2637,8 +3412,11 @@ class ChannelManager extends Manager {
2637
3412
  }
2638
3413
  async deleteChannel(channelId) {
2639
3414
  await this.#rest.delete(Routes.channel(channelId));
3415
+ this.delete(channelId);
3416
+ }
3417
+ delete(channelId) {
2640
3418
  this.#messageManagers.delete(channelId);
2641
- super.delete(channelId);
3419
+ return super.delete(channelId);
2642
3420
  }
2643
3421
  send(channelId, options) {
2644
3422
  return this.messages(channelId).send(options);
@@ -2683,6 +3461,8 @@ class ChannelManager extends Manager {
2683
3461
  }
2684
3462
  async bulkDeleteMessages(channelId, messageIds) {
2685
3463
  const ids = [...messageIds];
3464
+ if (ids.length < 2 || ids.length > 100)
3465
+ throw new RangeError("bulkDelete requires between 2 and 100 message IDs.");
2686
3466
  await this.#rest.post(Routes.channelBulkDelete(channelId), {
2687
3467
  messages: ids
2688
3468
  });
@@ -2690,7 +3470,7 @@ class ChannelManager extends Manager {
2690
3470
  this.messages(channelId).delete(id);
2691
3471
  }
2692
3472
  async addReaction(channelId, messageId, emoji) {
2693
- await this.#rest.put(Routes.messageReactions(channelId, messageId, emoji));
3473
+ await this.#rest.put(`${Routes.messageReactions(channelId, messageId, emoji)}/@me`);
2694
3474
  }
2695
3475
  async fetchReactions(channelId, messageId, emoji, options = {}) {
2696
3476
  const params = new URLSearchParams;
@@ -2724,9 +3504,21 @@ class ChannelManager extends Manager {
2724
3504
  createThreadFromMessage(channelId, messageId, options) {
2725
3505
  return this.threads(channelId).createFromMessage(messageId, options);
2726
3506
  }
2727
- delete(channelId) {
2728
- this.#messageManagers.delete(channelId);
2729
- return super.delete(channelId);
3507
+ async fetchPage(channelId, options = {}) {
3508
+ const limit = Math.min(100, Math.max(1, options.limit ?? 50));
3509
+ const messages = await this.fetchMessages(channelId, {
3510
+ ...options,
3511
+ limit
3512
+ });
3513
+ return {
3514
+ messages,
3515
+ before: messages[0]?.id,
3516
+ after: messages[messages.length - 1]?.id,
3517
+ hasMore: messages.length === limit
3518
+ };
3519
+ }
3520
+ async bulkDelete(channelId, messageIds) {
3521
+ return this.bulkDeleteMessages(channelId, messageIds);
2730
3522
  }
2731
3523
  clear() {
2732
3524
  this.#messageManagers.clear();
@@ -2751,6 +3543,22 @@ var GatewayOpcodes = {
2751
3543
  Hello: 10,
2752
3544
  HeartbeatAck: 11
2753
3545
  };
3546
+ var GatewayCloseCodes = {
3547
+ UnknownError: 4000,
3548
+ UnknownOpcode: 4001,
3549
+ DecodeError: 4002,
3550
+ NotAuthenticated: 4003,
3551
+ AuthenticationFailed: 4004,
3552
+ AlreadyAuthenticated: 4005,
3553
+ InvalidSeq: 4007,
3554
+ RateLimited: 4008,
3555
+ SessionTimedOut: 4009,
3556
+ InvalidShard: 4010,
3557
+ ShardingRequired: 4011,
3558
+ InvalidAPIVersion: 4012,
3559
+ InvalidIntents: 4013,
3560
+ DisallowedIntents: 4014
3561
+ };
2754
3562
  var GatewayState;
2755
3563
  ((GatewayState2) => {
2756
3564
  GatewayState2["Connect"] = "CONNECT";
@@ -2763,7 +3571,6 @@ var GatewayState;
2763
3571
  GatewayState2["Reconnect"] = "RECONNECT";
2764
3572
  GatewayState2["Closed"] = "CLOSED";
2765
3573
  })(GatewayState ||= {});
2766
-
2767
3574
  class GatewayError extends Error {
2768
3575
  code;
2769
3576
  constructor(message, code, options) {
@@ -2797,6 +3604,8 @@ class Gateway {
2797
3604
  #rejectConnect;
2798
3605
  #listeners = new Map;
2799
3606
  #sendTimestamps = [];
3607
+ ping = -1;
3608
+ #decompressor;
2800
3609
  constructor(options) {
2801
3610
  if (!options.token?.trim())
2802
3611
  throw new TypeError("A Gateway token is required.");
@@ -2817,7 +3626,12 @@ class Gateway {
2817
3626
  browser: "Discord Android",
2818
3627
  device: "Discord Android"
2819
3628
  },
2820
- presence: { status: "online", activities: [], afk: false, since: null },
3629
+ presence: {
3630
+ status: "online",
3631
+ activities: [],
3632
+ afk: false,
3633
+ since: null
3634
+ },
2821
3635
  ...options
2822
3636
  };
2823
3637
  if (this.#options.shardId < 0 || this.#options.shardId >= this.#options.shardCount)
@@ -2832,10 +3646,13 @@ class Gateway {
2832
3646
  return this.#connectPromise;
2833
3647
  this.#closed = false;
2834
3648
  this.#setState("CONNECT" /* Connect */);
3649
+ const connectURL = this.#options.compress ? url.includes("compress=") ? url : `${url}&compress=zlib-stream` : url;
3650
+ if (this.#options.compress)
3651
+ this.#initDecompressor();
2835
3652
  this.#connectPromise = new Promise((resolve, reject) => {
2836
3653
  this.#resolveConnect = resolve;
2837
3654
  this.#rejectConnect = reject;
2838
- this.#open(url);
3655
+ this.#open(connectURL);
2839
3656
  });
2840
3657
  return this.#connectPromise;
2841
3658
  }
@@ -2871,12 +3688,15 @@ class Gateway {
2871
3688
  send(payload) {
2872
3689
  if (!payload || !Number.isInteger(payload.op))
2873
3690
  throw new TypeError("Gateway payload must contain an integer opcode.");
3691
+ return this.#dispatch(payload, false);
3692
+ }
3693
+ #dispatch(payload, privileged) {
2874
3694
  if (this.#ws?.readyState !== WebSocket.OPEN)
2875
3695
  return false;
2876
3696
  const now = Date.now();
2877
3697
  while (this.#sendTimestamps.length && now - this.#sendTimestamps[0] >= 60000)
2878
3698
  this.#sendTimestamps.shift();
2879
- if (this.#sendTimestamps.length >= 115) {
3699
+ if (!privileged && this.#sendTimestamps.length >= 115) {
2880
3700
  this.#emitError(new GatewayError("Gateway send rate budget exhausted."));
2881
3701
  return false;
2882
3702
  }
@@ -2947,7 +3767,11 @@ class Gateway {
2947
3767
  ws.addEventListener("message", (event) => {
2948
3768
  this.#lastMessageAt = Date.now();
2949
3769
  this.#zombieReported = false;
2950
- this.#message(ws, String(event.data));
3770
+ if (this.#options.compress && event.data instanceof ArrayBuffer) {
3771
+ this.#decompress(new Uint8Array(event.data)).then((text) => this.#message(ws, text)).catch((err) => this.#emitError(err));
3772
+ } else {
3773
+ this.#message(ws, String(event.data));
3774
+ }
2951
3775
  });
2952
3776
  ws.addEventListener("close", (event) => this.#close(ws, event.code));
2953
3777
  ws.addEventListener("error", () => this.#emitError(new GatewayError("Gateway WebSocket error")));
@@ -2955,7 +3779,7 @@ class Gateway {
2955
3779
  #startZombieDetection() {
2956
3780
  if (this.#zombieTimer)
2957
3781
  clearInterval(this.#zombieTimer);
2958
- const interval = Math.max(1, Math.min(250, this.#options.heartbeatAckTimeout, this.#options.zombieTimeout / 2));
3782
+ const interval = Math.max(1, Math.min(1000, this.#options.heartbeatAckTimeout, this.#options.zombieTimeout / 2));
2959
3783
  this.#zombieTimer = setInterval(() => {
2960
3784
  if (this.#closed || this.#ws?.readyState !== WebSocket.OPEN || this.#lastMessageAt === 0)
2961
3785
  return;
@@ -3006,18 +3830,24 @@ class Gateway {
3006
3830
  break;
3007
3831
  case GatewayOpcodes.HeartbeatAck:
3008
3832
  this.#heartbeatACK = true;
3833
+ this.ping = Date.now() - this.#heartbeatSentAt;
3009
3834
  this.#clearHeartbeatAckTimer();
3010
3835
  this.#emit("heartbeatAck", payload.d);
3011
3836
  break;
3012
3837
  case GatewayOpcodes.Reconnect:
3013
3838
  ws.close(1001, "Server requested reconnect");
3014
3839
  break;
3015
- case GatewayOpcodes.InvalidSession:
3016
- this.#sessionId = undefined;
3017
- this.#sequence = null;
3018
- this.#emit("invalidSession", payload.d);
3019
- ws.close(1000, "Invalid session");
3840
+ case GatewayOpcodes.InvalidSession: {
3841
+ const resumable = payload.d === true;
3842
+ if (!resumable) {
3843
+ this.#sessionId = undefined;
3844
+ this.#sequence = null;
3845
+ this.#resumeURL = undefined;
3846
+ }
3847
+ this.#emit("invalidSession", resumable);
3848
+ ws.close(resumable ? GatewayCloseCodes.UnknownError : 1000, resumable ? "Invalid session (resumable)" : "Invalid session");
3020
3849
  break;
3850
+ }
3021
3851
  }
3022
3852
  }
3023
3853
  #handleDispatch(event, data) {
@@ -3032,6 +3862,10 @@ class Gateway {
3032
3862
  this.#attempt = 0;
3033
3863
  this.#setState("READY" /* Ready */);
3034
3864
  this.#emit("ready", data);
3865
+ } else if (event === "RESUMED") {
3866
+ this.#attempt = 0;
3867
+ this.#setState("READY" /* Ready */);
3868
+ this.#emit("resumed", data);
3035
3869
  }
3036
3870
  this.#emit("RAW", { event: event ?? "UNKNOWN", data });
3037
3871
  if (this.#closed)
@@ -3109,12 +3943,12 @@ class Gateway {
3109
3943
  #sendHeartbeat() {
3110
3944
  this.#heartbeatACK = false;
3111
3945
  this.#heartbeatSentAt = Date.now();
3112
- if (!this.send({
3946
+ if (!this.#dispatch({
3113
3947
  op: GatewayOpcodes.Heartbeat,
3114
3948
  d: this.#sequence,
3115
3949
  s: null,
3116
3950
  t: null
3117
- })) {
3951
+ }, true)) {
3118
3952
  this.#emitError(new GatewayError("Unable to send Gateway heartbeat because the WebSocket is not open."));
3119
3953
  return;
3120
3954
  }
@@ -3147,14 +3981,23 @@ class Gateway {
3147
3981
  if (action === "identify") {
3148
3982
  this.#sequence = null;
3149
3983
  this.#sessionId = undefined;
3984
+ this.#resumeURL = undefined;
3150
3985
  }
3151
3986
  this.#setState("RECONNECT" /* Reconnect */);
3152
3987
  this.#scheduleReconnect();
3153
3988
  }
3154
3989
  #closeAction(code) {
3155
- if ([4004, 4010, 4011, 4012, 4013, 4014].includes(code))
3990
+ const fatal = [
3991
+ GatewayCloseCodes.AuthenticationFailed,
3992
+ GatewayCloseCodes.InvalidShard,
3993
+ GatewayCloseCodes.ShardingRequired,
3994
+ GatewayCloseCodes.InvalidAPIVersion,
3995
+ GatewayCloseCodes.InvalidIntents,
3996
+ GatewayCloseCodes.DisallowedIntents
3997
+ ];
3998
+ if (fatal.includes(code))
3156
3999
  return "stop";
3157
- if ([4007, 4009].includes(code))
4000
+ if (code === GatewayCloseCodes.InvalidSeq || code === GatewayCloseCodes.SessionTimedOut)
3158
4001
  return "identify";
3159
4002
  return this.#sessionId && this.#sequence !== null ? "resume" : "identify";
3160
4003
  }
@@ -3167,7 +4010,7 @@ class Gateway {
3167
4010
  return;
3168
4011
  }
3169
4012
  const delay = Math.min(this.#options.reconnectMaxDelay, this.#options.reconnectBaseDelay * 2 ** this.#attempt++);
3170
- const jitter = Math.random() * Math.min(250, Math.max(1, delay * 0.25));
4013
+ const jitter = Math.random() * Math.max(1, delay * 0.25);
3171
4014
  this.#reconnectTimer = setTimeout(() => {
3172
4015
  this.#reconnectTimer = undefined;
3173
4016
  this.#open(this.#resumeURL ?? "wss://gateway.discord.gg/?v=10&encoding=json");
@@ -3237,10 +4080,41 @@ class Gateway {
3237
4080
  this.state = next;
3238
4081
  this.#emit("stateChange", { previous, next });
3239
4082
  }
4083
+ #initDecompressor() {
4084
+ const ds = new DecompressionStream("deflate-raw");
4085
+ this.#decompressor = {
4086
+ writer: ds.writable.getWriter(),
4087
+ reader: ds.readable.getReader()
4088
+ };
4089
+ }
4090
+ async#decompress(chunk) {
4091
+ if (!this.#decompressor)
4092
+ this.#initDecompressor();
4093
+ const { writer, reader } = this.#decompressor;
4094
+ await writer.write(chunk);
4095
+ const parts = [];
4096
+ while (true) {
4097
+ const { done, value } = await Promise.race([
4098
+ reader.read(),
4099
+ new Promise((resolve) => setTimeout(() => resolve({ done: true, value: undefined }), 50))
4100
+ ]);
4101
+ if (done || !value)
4102
+ break;
4103
+ parts.push(value);
4104
+ }
4105
+ const total = parts.reduce((n, p) => n + p.length, 0);
4106
+ const merged = new Uint8Array(total);
4107
+ let offset = 0;
4108
+ for (const p of parts) {
4109
+ merged.set(p, offset);
4110
+ offset += p.length;
4111
+ }
4112
+ return new TextDecoder().decode(merged);
4113
+ }
3240
4114
  }
3241
4115
 
3242
4116
  // packages/core/src/index.ts
3243
- class EventEmitter {
4117
+ class EventEmitter2 {
3244
4118
  #listeners = new Map;
3245
4119
  on(event, listener) {
3246
4120
  if (typeof listener !== "function")
@@ -3262,6 +4136,9 @@ class EventEmitter {
3262
4136
  this.#listeners.get(event)?.delete(listener);
3263
4137
  return this;
3264
4138
  }
4139
+ removeListener(event, listener) {
4140
+ return this.off(event, listener);
4141
+ }
3265
4142
  removeAllListeners(event) {
3266
4143
  if (event === undefined)
3267
4144
  this.#listeners.clear();
@@ -3298,7 +4175,7 @@ class EventEmitter {
3298
4175
  }
3299
4176
  }
3300
4177
 
3301
- class Client extends EventEmitter {
4178
+ class Client extends EventEmitter2 {
3302
4179
  options;
3303
4180
  rest;
3304
4181
  users;
@@ -3314,14 +4191,26 @@ class Client extends EventEmitter {
3314
4191
  user;
3315
4192
  readyAt;
3316
4193
  state = "idle";
4194
+ get token() {
4195
+ return this.state === "destroyed" ? null : this.options.token ?? null;
4196
+ }
3317
4197
  get uptime() {
3318
4198
  return this.readyAt ? Date.now() - this.readyAt.getTime() : null;
3319
4199
  }
4200
+ get ping() {
4201
+ return this.#gateway.ping;
4202
+ }
3320
4203
  isReady() {
3321
4204
  return this.state === "ready";
3322
4205
  }
3323
4206
  setPresence(data) {
3324
- return this.#gateway.setPresence?.(data) ?? false;
4207
+ return this.#gateway.setPresence(data);
4208
+ }
4209
+ setVoiceState(data) {
4210
+ return this.#gateway.setVoiceState(data);
4211
+ }
4212
+ requestGuildMembers(data) {
4213
+ return this.#gateway.requestGuildMembers(data);
3325
4214
  }
3326
4215
  #gateway;
3327
4216
  #resourceContext;
@@ -3365,6 +4254,13 @@ class Client extends EventEmitter {
3365
4254
  this.application.commands = new ApplicationCommandManager(this.rest, appId);
3366
4255
  this.emit("ready" /* Ready */, this.user);
3367
4256
  });
4257
+ this.#gateway.on("RESUMED", () => {
4258
+ this.state = "ready";
4259
+ this.emit("resumed" /* Resumed */);
4260
+ });
4261
+ this.#gateway.on("invalidSession", (isRecoverable) => {
4262
+ this.emit("invalidSession" /* InvalidSession */, isRecoverable);
4263
+ });
3368
4264
  this.#gateway.on("open", () => this.emit("open" /* Open */));
3369
4265
  this.#gateway.on("close", (data) => {
3370
4266
  if (this.state !== "destroyed")
@@ -3397,6 +4293,7 @@ class Client extends EventEmitter {
3397
4293
  this.emit("guildUnavailable" /* GuildUnavailable */, payload);
3398
4294
  return;
3399
4295
  }
4296
+ const wasCached = this.guilds.has(payload.id);
3400
4297
  const guild = new Guild(payload);
3401
4298
  this.guilds.set(guild.id, guild);
3402
4299
  for (const member of payload.members ?? [])
@@ -3406,7 +4303,7 @@ class Client extends EventEmitter {
3406
4303
  ...payload.threads ?? []
3407
4304
  ])
3408
4305
  this.channels.set(channelData.id, new Channel(channelData, this.#resourceContext));
3409
- this.emit("guildCreate" /* GuildCreate */, payload);
4306
+ this.emit(wasCached ? "guildAvailable" /* GuildAvailable */ : "guildCreate" /* GuildCreate */, payload);
3410
4307
  });
3411
4308
  this.#gateway.on("GUILD_UPDATE", (data) => {
3412
4309
  const guild = new Guild(data);
@@ -3535,6 +4432,47 @@ class Client extends EventEmitter {
3535
4432
  return Promise.reject(new Error("Client is unauthenticated."));
3536
4433
  return this.rest.post(`/webhooks/${this.user.id}/${token}`, data);
3537
4434
  }
4435
+ fetchWebhook(id, token) {
4436
+ return this.rest.get(token ? `/webhooks/${id}/${token}` : `/webhooks/${id}`);
4437
+ }
4438
+ fetchGuildPreview(guildId) {
4439
+ return this.rest.get(`/guilds/${guildId}/preview`);
4440
+ }
4441
+ fetchVoiceRegions() {
4442
+ return this.rest.get("/voice/regions");
4443
+ }
4444
+ fetchInvite(code, options) {
4445
+ const query = new URLSearchParams;
4446
+ if (options?.withCounts)
4447
+ query.set("with_counts", "true");
4448
+ if (options?.withExpiration)
4449
+ query.set("with_expiration", "true");
4450
+ if (options?.guildScheduledEventId)
4451
+ query.set("guild_scheduled_event_id", options.guildScheduledEventId);
4452
+ const qs = query.toString();
4453
+ return this.rest.get(`/invites/${code}${qs ? `?${qs}` : ""}`);
4454
+ }
4455
+ fetchSticker(id) {
4456
+ return this.rest.get(`/stickers/${id}`);
4457
+ }
4458
+ fetchPremiumStickerPacks() {
4459
+ return this.rest.get(`/sticker-packs`);
4460
+ }
4461
+ fetchGuildTemplate(code) {
4462
+ return this.rest.get(`/guilds/templates/${code}`);
4463
+ }
4464
+ generateInvite(options) {
4465
+ if (!this.user)
4466
+ throw new Error("Client must be ready to generate invite.");
4467
+ const params = new URLSearchParams({
4468
+ client_id: this.user.id,
4469
+ scopes: (options?.scopes ?? ["bot"]).join(" ")
4470
+ });
4471
+ if (options?.permissions) {
4472
+ params.set("permissions", String(options.permissions));
4473
+ }
4474
+ return `https://discord.com/api/oauth2/authorize?${params.toString()}`;
4475
+ }
3538
4476
  }
3539
4477
  // packages/formatters/src/index.ts
3540
4478
  function userMention(id) {
@@ -3553,6 +4491,55 @@ function timestamp(unixSeconds, style) {
3553
4491
  throw new RangeError("Invalid Discord timestamp style.");
3554
4492
  return `<t:${Math.floor(unixSeconds)}${style ? `:${style}` : ""}>`;
3555
4493
  }
4494
+ function bold(text) {
4495
+ return `**${text}**`;
4496
+ }
4497
+ function italic(text) {
4498
+ return `_${text}_`;
4499
+ }
4500
+ function underline(text) {
4501
+ return `__${text}__`;
4502
+ }
4503
+ function strikethrough(text) {
4504
+ return `~~${text}~~`;
4505
+ }
4506
+ function spoiler(text) {
4507
+ return `||${text}||`;
4508
+ }
4509
+ function masked(text) {
4510
+ return spoiler(text);
4511
+ }
4512
+ function inlineCode(text) {
4513
+ return `\`${text}\``;
4514
+ }
4515
+ function codeBlock(text, language = "") {
4516
+ return `\`\`\`${language}
4517
+ ${text}
4518
+ \`\`\``;
4519
+ }
4520
+ function link(label, url, title) {
4521
+ const titlePart = title ? ` "${title}"` : "";
4522
+ return `[${label}](${url}${titlePart})`;
4523
+ }
4524
+ function blockQuote(text) {
4525
+ return text.split(`
4526
+ `).map((line) => `> ${line}`).join(`
4527
+ `);
4528
+ }
4529
+ function heading(text, level = 1) {
4530
+ return `${"#".repeat(level)} ${text}`;
4531
+ }
4532
+ function subtext(text) {
4533
+ return `-# ${text}`;
4534
+ }
4535
+ function orderedList(...items) {
4536
+ return items.map((item, i) => `${i + 1}. ${item}`).join(`
4537
+ `);
4538
+ }
4539
+ function bulletList(...items) {
4540
+ return items.map((item) => `- ${item}`).join(`
4541
+ `);
4542
+ }
3556
4543
  function escapeMarkdown(value) {
3557
4544
  return value.replace(/[\\*_`~|>]/g, "\\$&");
3558
4545
  }
@@ -3673,8 +4660,155 @@ class ShardBus {
3673
4660
  }
3674
4661
  }
3675
4662
  }
4663
+ // packages/sharding/src/cluster.ts
4664
+ import { fork } from "child_process";
4665
+ import { cpus } from "os";
4666
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
4667
+
4668
+ class ClusterManager {
4669
+ clusters = new Map;
4670
+ shardCount = 0;
4671
+ #options;
4672
+ #auto;
4673
+ #autoScaleTimer;
4674
+ #spawned = false;
4675
+ constructor(options) {
4676
+ if (!options.token?.trim())
4677
+ throw new TypeError("A Discord bot token is required.");
4678
+ if (!options.script?.trim())
4679
+ throw new TypeError("A script path is required for clustering.");
4680
+ if (options.autoScaleInterval !== undefined && (!Number.isInteger(options.autoScaleInterval) || options.autoScaleInterval < 1000)) {
4681
+ throw new RangeError("autoScaleInterval must be an integer of at least 1000 milliseconds.");
4682
+ }
4683
+ this.#auto = options.shardCount === "auto";
4684
+ this.#options = { ...options };
4685
+ }
4686
+ async fetchRecommendedShardCount() {
4687
+ const response = await fetch("https://discord.com/api/v10/gateway/bot", {
4688
+ headers: {
4689
+ Authorization: `Bot ${this.#options.token}`,
4690
+ "User-Agent": "Lunibee/0.1.0"
4691
+ }
4692
+ });
4693
+ if (!response.ok) {
4694
+ throw new Error(`Gateway discovery failed with status ${response.status}`);
4695
+ }
4696
+ const data = await response.json();
4697
+ if (typeof data.shards !== "number" || !Number.isInteger(data.shards) || data.shards < 1) {
4698
+ throw new Error("Gateway discovery returned an invalid shard count.");
4699
+ }
4700
+ return data.shards;
4701
+ }
4702
+ async spawn() {
4703
+ if (this.#spawned)
4704
+ return;
4705
+ if (typeof process?.versions?.bun === "string") {
4706
+ throw new Error("ClusterManager requires the Node.js runtime; Bun does not support child_process.fork() for this clustering mode.");
4707
+ }
4708
+ this.#spawned = true;
4709
+ const count = this.#options.shardCount === "auto" || this.#options.shardCount === undefined ? await this.fetchRecommendedShardCount() : this.#options.shardCount;
4710
+ this.shardCount = count;
4711
+ const clusterCount = this.#options.clusterCount ?? cpus().length;
4712
+ const chunks = Array.from({ length: clusterCount }, () => []);
4713
+ for (let i = 0;i < count; i++) {
4714
+ chunks[i % clusterCount].push(i);
4715
+ }
4716
+ for (let i = 0;i < clusterCount; i++) {
4717
+ if (chunks[i].length === 0)
4718
+ continue;
4719
+ const child = fork(this.#options.script, [], {
4720
+ env: {
4721
+ ...process.env,
4722
+ SHARD_LIST: chunks[i].join(","),
4723
+ SHARD_COUNT: count.toString(),
4724
+ CLUSTER_ID: i.toString()
4725
+ }
4726
+ });
4727
+ this.clusters.set(i, {
4728
+ id: i,
4729
+ process: child,
4730
+ shards: chunks[i]
4731
+ });
4732
+ await sleep(500);
4733
+ }
4734
+ if (this.#options.autoScaleInterval && this.#options.autoScaleInterval > 0) {
4735
+ this.#autoScaleTimer = setInterval(() => {
4736
+ this.checkAutoScale();
4737
+ }, this.#options.autoScaleInterval);
4738
+ }
4739
+ }
4740
+ async checkAutoScale() {
4741
+ if (!this.#auto)
4742
+ return;
4743
+ try {
4744
+ const recommended = await this.fetchRecommendedShardCount();
4745
+ if (recommended !== this.shardCount) {
4746
+ await this.respawn(recommended);
4747
+ }
4748
+ } catch (error) {
4749
+ const normalized = error instanceof Error ? error : new Error(String(error));
4750
+ this.#options.onAutoScaleError?.(normalized);
4751
+ }
4752
+ }
4753
+ async respawn(newShardCount) {
4754
+ this.#options.shardCount = newShardCount;
4755
+ await this.shutdownAll();
4756
+ this.#spawned = false;
4757
+ await this.spawn();
4758
+ }
4759
+ async shutdownAll(timeoutMs = this.#options.shutdownTimeout ?? 5000) {
4760
+ if (this.#autoScaleTimer) {
4761
+ clearInterval(this.#autoScaleTimer);
4762
+ this.#autoScaleTimer = undefined;
4763
+ }
4764
+ await Promise.all([...this.clusters.values()].map((cluster) => this.#shutdownCluster(cluster, timeoutMs)));
4765
+ this.clusters.clear();
4766
+ this.#spawned = false;
4767
+ }
4768
+ async#shutdownCluster(cluster, timeoutMs) {
4769
+ const child = cluster.process;
4770
+ if (child.exitCode !== null || child.signalCode !== null)
4771
+ return;
4772
+ await new Promise((resolve) => {
4773
+ let timer;
4774
+ const finish = () => {
4775
+ if (timer)
4776
+ clearTimeout(timer);
4777
+ resolve();
4778
+ };
4779
+ child.once("exit", finish);
4780
+ try {
4781
+ child.kill("SIGTERM");
4782
+ } catch {
4783
+ child.off("exit", finish);
4784
+ finish();
4785
+ return;
4786
+ }
4787
+ timer = setTimeout(() => {
4788
+ try {
4789
+ child.kill("SIGKILL");
4790
+ } catch {}
4791
+ }, timeoutMs);
4792
+ });
4793
+ }
4794
+ killAll() {
4795
+ if (this.#autoScaleTimer) {
4796
+ clearInterval(this.#autoScaleTimer);
4797
+ this.#autoScaleTimer = undefined;
4798
+ }
4799
+ for (const cluster of this.clusters.values()) {
4800
+ try {
4801
+ cluster.process.kill();
4802
+ } catch {}
4803
+ }
4804
+ this.clusters.clear();
4805
+ this.#spawned = false;
4806
+ }
4807
+ }
3676
4808
 
3677
4809
  // packages/sharding/src/index.ts
4810
+ var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
4811
+
3678
4812
  class ShardManager {
3679
4813
  shards = new Map;
3680
4814
  get shardCount() {
@@ -3683,6 +4817,8 @@ class ShardManager {
3683
4817
  #options;
3684
4818
  #resolved = false;
3685
4819
  #destroyed = false;
4820
+ #auto;
4821
+ #autoScaleTimer;
3686
4822
  constructor(options) {
3687
4823
  if (!options.token?.trim())
3688
4824
  throw new TypeError("A Discord bot token is required.");
@@ -3691,6 +4827,9 @@ class ShardManager {
3691
4827
  const count = options.shardCount === "auto" || options.shardCount === undefined ? 1 : options.shardCount;
3692
4828
  if (!Number.isInteger(count) || count < 1)
3693
4829
  throw new RangeError("Shard count must be a positive integer.");
4830
+ if (options.autoScaleInterval !== undefined && (!Number.isInteger(options.autoScaleInterval) || options.autoScaleInterval < 1000))
4831
+ throw new RangeError("autoScaleInterval must be an integer of at least 1000 milliseconds.");
4832
+ this.#auto = options.shardCount === "auto";
3694
4833
  this.#options = { ...options };
3695
4834
  if (options.shardCount !== "auto")
3696
4835
  this.#initialize(count);
@@ -3710,24 +4849,56 @@ class ShardManager {
3710
4849
  return data.shards;
3711
4850
  }
3712
4851
  async connect() {
4852
+ if (this.#autoScaleTimer) {
4853
+ clearInterval(this.#autoScaleTimer);
4854
+ this.#autoScaleTimer = undefined;
4855
+ }
3713
4856
  await this.#ensureInitialized();
3714
4857
  for (const [id, shard] of this.shards) {
3715
4858
  try {
3716
4859
  await shard.connect();
3717
4860
  } catch (error) {
3718
4861
  this.destroy();
3719
- throw new Error(`Failed to connect shard ${id}.`, { cause: error });
4862
+ throw new Error(`Failed to connect shard ${id}.`, {
4863
+ cause: error
4864
+ });
3720
4865
  }
3721
4866
  if (id + 1 < this.shardCount && this.#options.spawnDelay && this.#options.spawnDelay > 0)
3722
- await Bun.sleep(this.#options.spawnDelay);
4867
+ await sleep2(this.#options.spawnDelay);
4868
+ }
4869
+ if (this.#options.autoScaleInterval && !this.#autoScaleTimer) {
4870
+ this.#autoScaleTimer = setInterval(() => {
4871
+ this.checkAutoScale();
4872
+ }, this.#options.autoScaleInterval);
4873
+ }
4874
+ }
4875
+ async checkAutoScale() {
4876
+ if (!this.#auto)
4877
+ return;
4878
+ try {
4879
+ const recommended = await this.fetchRecommendedShardCount();
4880
+ if (recommended !== this.shardCount) {
4881
+ await this.reshard(recommended);
4882
+ }
4883
+ } catch (error) {
4884
+ this.#options.onAutoScaleError?.(error);
3723
4885
  }
3724
4886
  }
4887
+ async reshard(count) {
4888
+ this.#options.shardCount = count;
4889
+ this.destroy();
4890
+ await this.connect();
4891
+ }
3725
4892
  destroy() {
3726
4893
  for (const shard of this.shards.values())
3727
4894
  shard.close();
3728
4895
  this.shards.clear();
3729
4896
  this.#resolved = false;
3730
4897
  this.#destroyed = true;
4898
+ if (this.#autoScaleTimer) {
4899
+ clearInterval(this.#autoScaleTimer);
4900
+ this.#autoScaleTimer = undefined;
4901
+ }
3731
4902
  }
3732
4903
  getShardIdForGuild(guildId) {
3733
4904
  const id = BigInt(guildId);
@@ -3765,7 +4936,7 @@ class ShardManager {
3765
4936
  }
3766
4937
  }
3767
4938
  // packages/utils/src/index.ts
3768
- function sleep(ms) {
4939
+ function sleep3(ms) {
3769
4940
  return new Promise((resolve) => setTimeout(resolve, ms));
3770
4941
  }
3771
4942
  function randomInt(min, max) {
@@ -3804,6 +4975,7 @@ class VoiceConnection {
3804
4975
  gateway;
3805
4976
  udp;
3806
4977
  #listeners = new Map;
4978
+ receiver;
3807
4979
  constructor(options) {
3808
4980
  const resolved = typeof options === "string" ? { guildId: options } : options;
3809
4981
  if (!resolved.guildId?.trim()) {
@@ -3813,6 +4985,7 @@ class VoiceConnection {
3813
4985
  this.channelId = resolved.channelId;
3814
4986
  this.selfMute = resolved.selfMute ?? false;
3815
4987
  this.selfDeaf = resolved.selfDeaf ?? false;
4988
+ this.receiver = new VoiceReceiver(this);
3816
4989
  }
3817
4990
  on(event, listener) {
3818
4991
  if (typeof listener !== "function")
@@ -3835,6 +5008,13 @@ class VoiceConnection {
3835
5008
  this.#closeTransports();
3836
5009
  this.gateway = gateway;
3837
5010
  this.udp = udp;
5011
+ const attachedUdp = udp;
5012
+ if (attachedUdp.onMessage) {
5013
+ attachedUdp.onMessage((packet) => {
5014
+ if (this.udp === attachedUdp)
5015
+ this.receiver.onPacket(packet);
5016
+ });
5017
+ }
3838
5018
  return this;
3839
5019
  }
3840
5020
  connect() {
@@ -3890,12 +5070,16 @@ class VoiceConnection {
3890
5070
  try {
3891
5071
  this.gateway?.close(1000, "Voice connection replaced or closed");
3892
5072
  } catch (error) {
3893
- this.#emit("error", error instanceof VoiceError ? error : new VoiceError("Voice gateway cleanup failed.", { cause: error }));
5073
+ this.#emit("error", error instanceof VoiceError ? error : new VoiceError("Voice gateway cleanup failed.", {
5074
+ cause: error
5075
+ }));
3894
5076
  }
3895
5077
  try {
3896
5078
  this.udp?.close();
3897
5079
  } catch (error) {
3898
- this.#emit("error", error instanceof VoiceError ? error : new VoiceError("Voice UDP cleanup failed.", { cause: error }));
5080
+ this.#emit("error", error instanceof VoiceError ? error : new VoiceError("Voice UDP cleanup failed.", {
5081
+ cause: error
5082
+ }));
3899
5083
  }
3900
5084
  this.gateway = undefined;
3901
5085
  this.udp = undefined;
@@ -3909,7 +5093,9 @@ class VoiceConnection {
3909
5093
  try {
3910
5094
  listener(next, previous);
3911
5095
  } catch (error) {
3912
- this.#emit("error", error instanceof VoiceError ? error : new VoiceError("Voice event listener failed.", { cause: error }));
5096
+ this.#emit("error", error instanceof VoiceError ? error : new VoiceError("Voice event listener failed.", {
5097
+ cause: error
5098
+ }));
3913
5099
  }
3914
5100
  if (this.state !== next && next !== "destroyed" /* Destroyed */)
3915
5101
  return;
@@ -3926,6 +5112,187 @@ class VoiceConnection {
3926
5112
  this.#assertUsable();
3927
5113
  }
3928
5114
  }
5115
+
5116
+ class AudioStream {
5117
+ stream;
5118
+ title;
5119
+ duration;
5120
+ constructor(stream, metadata) {
5121
+ this.stream = stream;
5122
+ this.title = metadata?.title;
5123
+ this.duration = metadata?.duration;
5124
+ }
5125
+ }
5126
+
5127
+ class AudioPlayer {
5128
+ #state = "idle";
5129
+ #stream;
5130
+ #reader;
5131
+ #resumeSignal;
5132
+ #listeners = new Map;
5133
+ get state() {
5134
+ return this.#state;
5135
+ }
5136
+ get current() {
5137
+ return this.#stream;
5138
+ }
5139
+ async play(audioStream) {
5140
+ if (this.#state === "playing" || this.#state === "paused")
5141
+ await this.stop();
5142
+ this.#stream = audioStream;
5143
+ this.#reader = audioStream.stream.getReader();
5144
+ this.#transition("playing");
5145
+ this.#pump().catch((err) => this.#emitError(err));
5146
+ }
5147
+ pause() {
5148
+ if (this.#state !== "playing")
5149
+ return;
5150
+ this.#transition("paused");
5151
+ }
5152
+ resume() {
5153
+ if (this.#state !== "paused")
5154
+ return;
5155
+ this.#transition("playing");
5156
+ const signal = this.#resumeSignal;
5157
+ this.#resumeSignal = undefined;
5158
+ signal?.();
5159
+ }
5160
+ async stop() {
5161
+ if (this.#state === "idle" || this.#state === "stopped")
5162
+ return;
5163
+ const reader = this.#reader;
5164
+ this.#reader = undefined;
5165
+ this.#stream = undefined;
5166
+ this.#transition("stopped");
5167
+ const signal = this.#resumeSignal;
5168
+ this.#resumeSignal = undefined;
5169
+ signal?.();
5170
+ if (reader) {
5171
+ try {
5172
+ await reader.cancel();
5173
+ } catch {}
5174
+ }
5175
+ }
5176
+ on(event, listener) {
5177
+ let set = this.#listeners.get(event);
5178
+ if (!set) {
5179
+ this.#listeners.set(event, set = new Set);
5180
+ }
5181
+ set.add(listener);
5182
+ return this;
5183
+ }
5184
+ off(event, listener) {
5185
+ this.#listeners.get(event)?.delete(listener);
5186
+ return this;
5187
+ }
5188
+ onChunk(chunk) {}
5189
+ async#pump() {
5190
+ const reader = this.#reader;
5191
+ if (!reader)
5192
+ return;
5193
+ while (true) {
5194
+ if (this.#state === "paused") {
5195
+ await new Promise((resolve) => {
5196
+ this.#resumeSignal = resolve;
5197
+ });
5198
+ }
5199
+ if (this.#state !== "playing")
5200
+ return;
5201
+ const { done, value } = await reader.read();
5202
+ if (done) {
5203
+ if (this.#state === "playing" || this.#state === "paused") {
5204
+ this.#transition("idle");
5205
+ this.#stream = undefined;
5206
+ this.#reader = undefined;
5207
+ this.#emit("finish");
5208
+ }
5209
+ return;
5210
+ }
5211
+ if (this.#state !== "playing" && this.#state !== "paused")
5212
+ return;
5213
+ this.onChunk(value);
5214
+ }
5215
+ }
5216
+ #transition(next) {
5217
+ if (this.#state === next)
5218
+ return;
5219
+ const from = this.#state;
5220
+ this.#state = next;
5221
+ this.#emit("stateChange", from, next);
5222
+ }
5223
+ #emitError(err) {
5224
+ this.#emit("error", err instanceof Error ? err : new VoiceError(String(err)));
5225
+ }
5226
+ #emit(event, ...args) {
5227
+ for (const listener of this.#listeners.get(event) ?? []) {
5228
+ try {
5229
+ listener(...args);
5230
+ } catch {}
5231
+ }
5232
+ }
5233
+ }
5234
+
5235
+ class VoiceReceiver {
5236
+ connection;
5237
+ #ssrcMap = new Map;
5238
+ #streams = new Map;
5239
+ constructor(connection) {
5240
+ this.connection = connection;
5241
+ }
5242
+ mapSsrc(ssrc, userId) {
5243
+ this.#ssrcMap.set(ssrc, userId);
5244
+ }
5245
+ subscribe(userId) {
5246
+ let controllerRef;
5247
+ const stream = new ReadableStream({
5248
+ start: (controller) => {
5249
+ controllerRef = controller;
5250
+ let set = this.#streams.get(userId);
5251
+ if (!set)
5252
+ this.#streams.set(userId, set = new Set);
5253
+ set.add(controller);
5254
+ },
5255
+ cancel: () => {
5256
+ const set = this.#streams.get(userId);
5257
+ if (set) {
5258
+ set.delete(controllerRef);
5259
+ if (set.size === 0)
5260
+ this.#streams.delete(userId);
5261
+ }
5262
+ }
5263
+ });
5264
+ return new AudioStream(stream, { title: `User ${userId} Audio` });
5265
+ }
5266
+ onPacket(packet) {
5267
+ if (packet.length < 12)
5268
+ return;
5269
+ const view = new DataView(packet.buffer, packet.byteOffset, packet.byteLength);
5270
+ const ssrc = view.getUint32(8, false);
5271
+ const userId = this.#ssrcMap.get(ssrc);
5272
+ if (!userId)
5273
+ return;
5274
+ const controllers = this.#streams.get(userId);
5275
+ if (!controllers || controllers.size === 0)
5276
+ return;
5277
+ const csrcCount = packet[0] & 15;
5278
+ let offset = 12 + csrcCount * 4;
5279
+ const hasExtension = (packet[0] & 16) !== 0;
5280
+ if (hasExtension) {
5281
+ if (packet.length < offset + 4)
5282
+ return;
5283
+ const extWords = view.getUint16(offset + 2, false);
5284
+ offset += 4 + extWords * 4;
5285
+ }
5286
+ if (packet.length < offset)
5287
+ return;
5288
+ const payload = packet.slice(offset);
5289
+ for (const controller of controllers) {
5290
+ try {
5291
+ controller.enqueue(payload);
5292
+ } catch {}
5293
+ }
5294
+ }
5295
+ }
3929
5296
  // packages/builders/src/embed.ts
3930
5297
  class EmbedBuilder {
3931
5298
  #data = {};
@@ -3980,16 +5347,20 @@ class EmbedBuilder {
3980
5347
  return this;
3981
5348
  }
3982
5349
  addFields(...fields) {
3983
- if (!fields.length)
5350
+ const resolved = fields.length === 1 && Array.isArray(fields[0]) ? fields[0] : fields;
5351
+ if (!resolved.length)
3984
5352
  throw new TypeError("At least one embed field is required.");
3985
5353
  const current = this.#data.fields ?? [];
3986
- if (current.length + fields.length > 25)
5354
+ if (current.length + resolved.length > 25)
3987
5355
  throw new RangeError("An embed cannot contain more than 25 fields.");
3988
- for (const field of fields) {
5356
+ for (const field of resolved) {
3989
5357
  validate(field.name, 256, "Embed field name");
3990
5358
  validate(field.value, 1024, "Embed field value");
3991
5359
  }
3992
- this.#data.fields = [...current, ...fields.map((field) => ({ ...field }))];
5360
+ this.#data.fields = [
5361
+ ...current,
5362
+ ...resolved.map((field) => ({ ...field }))
5363
+ ];
3993
5364
  return this;
3994
5365
  }
3995
5366
  setFields(fields) {
@@ -4056,13 +5427,6 @@ var ComponentType = {
4056
5427
  ContentInventoryEntry: 16,
4057
5428
  Container: 17
4058
5429
  };
4059
- var ButtonStyle = {
4060
- Primary: 1,
4061
- Secondary: 2,
4062
- Success: 3,
4063
- Danger: 4,
4064
- Link: 5
4065
- };
4066
5430
  var TextInputStyle = { Short: 1, Paragraph: 2 };
4067
5431
 
4068
5432
  class ActionRowBuilder {
@@ -4171,7 +5535,9 @@ class ButtonBuilder {
4171
5535
  try {
4172
5536
  url2 = new URL(value);
4173
5537
  } catch (error) {
4174
- throw new TypeError("Button URL must be a valid URL.", { cause: error });
5538
+ throw new TypeError("Button URL must be a valid URL.", {
5539
+ cause: error
5540
+ });
4175
5541
  }
4176
5542
  this.#data.style = ButtonStyle.Link;
4177
5543
  delete this.#data.custom_id;
@@ -4227,7 +5593,7 @@ class EntitySelectBuilder {
4227
5593
  return this;
4228
5594
  }
4229
5595
  setDefaultValues(...values) {
4230
- this.#data.default_values = values;
5596
+ this.#data.default_values = values.map((value) => ({ ...value }));
4231
5597
  return this;
4232
5598
  }
4233
5599
  toJSON() {
@@ -4318,6 +5684,7 @@ class TextInputBuilder {
4318
5684
  class ContainerBuilder {
4319
5685
  #components = [];
4320
5686
  #accentColor;
5687
+ #spoiler;
4321
5688
  addComponents(...components) {
4322
5689
  if (!components.length)
4323
5690
  throw new TypeError("At least one component is required.");
@@ -4331,12 +5698,20 @@ class ContainerBuilder {
4331
5698
  this.#accentColor = color;
4332
5699
  return this;
4333
5700
  }
5701
+ setSpoiler(spoiler2 = true) {
5702
+ this.#spoiler = spoiler2;
5703
+ return this;
5704
+ }
4334
5705
  toJSON() {
4335
- return {
5706
+ const data = {
4336
5707
  type: ComponentType.Container,
4337
- components: this.#components.map((c) => c.toJSON()),
4338
- accent_color: this.#accentColor
5708
+ components: this.#components.map((c) => c.toJSON())
4339
5709
  };
5710
+ if (this.#accentColor !== undefined)
5711
+ data.accent_color = this.#accentColor;
5712
+ if (this.#spoiler !== undefined)
5713
+ data.spoiler = this.#spoiler;
5714
+ return data;
4340
5715
  }
4341
5716
  }
4342
5717
 
@@ -4405,8 +5780,8 @@ class FileComponentBuilder {
4405
5780
  this.#url = url2;
4406
5781
  return this;
4407
5782
  }
4408
- setSpoiler(spoiler = true) {
4409
- this.#spoiler = spoiler;
5783
+ setSpoiler(spoiler2 = true) {
5784
+ this.#spoiler = spoiler2;
4410
5785
  return this;
4411
5786
  }
4412
5787
  toJSON() {
@@ -4447,16 +5822,32 @@ class SeparatorBuilder {
4447
5822
 
4448
5823
  class ThumbnailBuilder {
4449
5824
  #url = "";
5825
+ #description;
5826
+ #spoiler;
4450
5827
  setUrl(url2) {
4451
5828
  validateText(url2, 2048, "Thumbnail URL");
4452
5829
  this.#url = url2;
4453
5830
  return this;
4454
5831
  }
5832
+ setDescription(description) {
5833
+ validateText(description, 1024, "Thumbnail description");
5834
+ this.#description = description;
5835
+ return this;
5836
+ }
5837
+ setSpoiler(spoiler2 = true) {
5838
+ this.#spoiler = spoiler2;
5839
+ return this;
5840
+ }
4455
5841
  toJSON() {
4456
- return {
5842
+ const data = {
4457
5843
  type: ComponentType.Thumbnail,
4458
5844
  url: this.#url
4459
5845
  };
5846
+ if (this.#description !== undefined)
5847
+ data.description = this.#description;
5848
+ if (this.#spoiler !== undefined)
5849
+ data.spoiler = this.#spoiler;
5850
+ return data;
4460
5851
  }
4461
5852
  }
4462
5853
 
@@ -4845,6 +6236,46 @@ function validateNumberRange(value, minimum, maximum, field, integerOnly = true)
4845
6236
  if (!Number.isFinite(value) || integerOnly && !Number.isInteger(value) || value < minimum || value > maximum)
4846
6237
  throw new RangeError(`${field} must be ${integerOnly ? "an integer" : "a number"} between ${minimum} and ${maximum}.`);
4847
6238
  }
6239
+
6240
+ class ContextMenuCommandBuilder {
6241
+ data;
6242
+ constructor(type) {
6243
+ this.data = { type };
6244
+ }
6245
+ setName(name) {
6246
+ if (typeof name !== "string" || name.trim().length < 1 || name.length > 32)
6247
+ throw new RangeError("Command name must contain 1-32 characters.");
6248
+ this.data.name = name;
6249
+ return this;
6250
+ }
6251
+ setDefaultMemberPermissions(permissions) {
6252
+ this.data.default_member_permissions = permissions === null ? null : BigInt(permissions).toString();
6253
+ return this;
6254
+ }
6255
+ setDMPermission(enabled) {
6256
+ this.data.dm_permission = enabled;
6257
+ return this;
6258
+ }
6259
+ setIntegrationTypes(...types) {
6260
+ this.data.integration_types = [...types];
6261
+ return this;
6262
+ }
6263
+ toJSON() {
6264
+ return structuredClone(this.data);
6265
+ }
6266
+ }
6267
+
6268
+ class UserCommandBuilder extends ContextMenuCommandBuilder {
6269
+ constructor() {
6270
+ super(2);
6271
+ }
6272
+ }
6273
+
6274
+ class MessageCommandBuilder extends ContextMenuCommandBuilder {
6275
+ constructor() {
6276
+ super(3);
6277
+ }
6278
+ }
4848
6279
  // packages/builders/src/attachment.ts
4849
6280
  import { readFile } from "fs/promises";
4850
6281
  import { basename } from "path";
@@ -4890,7 +6321,7 @@ class AttachmentBuilder {
4890
6321
  if (typeof Buffer !== "undefined" && Buffer.isBuffer(this.file)) {
4891
6322
  return new Uint8Array(this.file);
4892
6323
  }
4893
- return new Uint8Array;
6324
+ throw new TypeError("Attachment file must be a supported binary value or file path.");
4894
6325
  }
4895
6326
  }
4896
6327
  export {
@@ -4900,6 +6331,12 @@ export {
4900
6331
  ApplicationCommandType,
4901
6332
  AttachmentBuilder,
4902
6333
  AttachmentOptionBuilder,
6334
+ AudioPlayer,
6335
+ AudioStream,
6336
+ AuditLog,
6337
+ AuditLogEntry,
6338
+ AuditLogEvent,
6339
+ AutoModerationRule,
4903
6340
  AutocompleteInteraction,
4904
6341
  BaseStructure,
4905
6342
  BooleanOptionBuilder,
@@ -4912,18 +6349,24 @@ export {
4912
6349
  ChannelType,
4913
6350
  Client,
4914
6351
  ClientEvent,
6352
+ ClusterManager,
4915
6353
  Collection,
6354
+ Collector,
4916
6355
  CommandInteraction,
4917
6356
  CommandOptions,
4918
6357
  ComponentInteraction,
4919
6358
  ComponentType,
4920
6359
  ContainerBuilder,
4921
6360
  ContentInventoryEntryBuilder,
6361
+ RESTError as DiscordAPIError,
4922
6362
  Embed,
4923
6363
  EmbedBuilder,
6364
+ Emoji,
6365
+ EmojiManager,
4924
6366
  EntitySelectBuilder,
4925
6367
  FileComponentBuilder,
4926
6368
  Gateway,
6369
+ GatewayCloseCodes,
4927
6370
  GatewayError,
4928
6371
  GatewayIntentBits,
4929
6372
  GatewayOpcodes,
@@ -4932,6 +6375,8 @@ export {
4932
6375
  GuildManager,
4933
6376
  GuildMember,
4934
6377
  GuildMemberManager,
6378
+ GuildOnboarding,
6379
+ GuildWelcomeScreen,
4935
6380
  HandlerRegistry,
4936
6381
  IntegerOptionBuilder,
4937
6382
  IntentBits,
@@ -4940,15 +6385,20 @@ export {
4940
6385
  InteractionResponse,
4941
6386
  InteractionResponseType,
4942
6387
  InteractionType,
6388
+ Invite,
4943
6389
  Manager,
4944
6390
  MediaGalleryBuilder,
6391
+ MemoryRateLimitStore,
4945
6392
  MentionableOptionBuilder,
4946
6393
  Message,
6394
+ MessageCommandBuilder,
4947
6395
  MessageFlags,
4948
6396
  MessageManager,
4949
6397
  ModalBuilder,
4950
6398
  ModalSubmitInteraction,
4951
6399
  NumberOptionBuilder,
6400
+ OnboardingPrompt,
6401
+ OnboardingPromptOption,
4952
6402
  Permission,
4953
6403
  PermissionFlagsBits,
4954
6404
  PermissionOverwriteType,
@@ -4958,6 +6408,7 @@ export {
4958
6408
  PremiumTier,
4959
6409
  REST,
4960
6410
  RESTError,
6411
+ RedisRateLimitStore,
4961
6412
  ResourceManager,
4962
6413
  Role,
4963
6414
  RoleManager,
@@ -4969,6 +6420,7 @@ export {
4969
6420
  ShardManager,
4970
6421
  SlashCommandBuilder,
4971
6422
  SpeakingFlags,
6423
+ GatewayState as Status,
4972
6424
  StickerFormatType,
4973
6425
  StickerType,
4974
6426
  StringOptionBuilder,
@@ -4982,24 +6434,43 @@ export {
4982
6434
  ThreadManager,
4983
6435
  ThumbnailBuilder,
4984
6436
  User,
6437
+ UserCommandBuilder,
4985
6438
  UserManager,
4986
6439
  UserOptionBuilder,
4987
6440
  VerificationLevel,
4988
6441
  VoiceConnection,
4989
6442
  VoiceConnectionState,
4990
6443
  VoiceError,
6444
+ VoiceReceiver,
6445
+ Webhook,
4991
6446
  WebhookClient,
6447
+ WebhookType,
6448
+ WelcomeScreenChannel,
6449
+ blockQuote,
6450
+ bold,
6451
+ bulletList,
4992
6452
  channelMention,
6453
+ codeBlock,
4993
6454
  createInteraction,
4994
6455
  createRetryPolicy,
4995
6456
  escapeMarkdown,
6457
+ heading,
6458
+ inlineCode,
4996
6459
  isSnowflake,
6460
+ italic,
6461
+ link,
6462
+ masked,
6463
+ orderedList,
4997
6464
  randomInt,
4998
6465
  resolveGatewayIntents,
4999
6466
  roleMention,
5000
- sleep,
6467
+ sleep3 as sleep,
6468
+ spoiler,
6469
+ strikethrough,
6470
+ subtext,
5001
6471
  timestamp,
6472
+ underline,
5002
6473
  userMention
5003
6474
  };
5004
6475
 
5005
- //# debugId=0DD3C15D8E81668964756E2164756E21
6476
+ //# debugId=CB787B7E0E4365B464756E2164756E21