lunibee 0.1.4 → 0.1.6

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 (42) hide show
  1. package/README.md +12 -23
  2. package/dist/builders/components.d.ts +108 -0
  3. package/dist/builders/index.d.ts +1 -1
  4. package/dist/builders/index.js +178 -2
  5. package/dist/builders/index.js.map +3 -3
  6. package/dist/collection/index.d.ts +6 -0
  7. package/dist/collection/index.js +33 -2
  8. package/dist/collection/index.js.map +4 -4
  9. package/dist/core/events.d.ts +67 -3
  10. package/dist/core/index.d.ts +120 -90
  11. package/dist/core/index.js +816 -1021
  12. package/dist/core/index.js.map +20 -21
  13. package/dist/formatters/index.js.map +1 -1
  14. package/dist/index.d.ts +5 -4
  15. package/dist/index.js +2215 -1392
  16. package/dist/index.js.map +29 -26
  17. package/dist/managers/guild.d.ts +30 -0
  18. package/dist/managers/index.d.ts +56 -75
  19. package/dist/managers/index.js +339 -48
  20. package/dist/managers/index.js.map +16 -12
  21. package/dist/managers/message.d.ts +7 -12
  22. package/dist/managers/user.d.ts +20 -0
  23. package/dist/rest/index.d.ts +83 -1
  24. package/dist/rest/index.js +48 -8
  25. package/dist/rest/index.js.map +4 -4
  26. package/dist/rest/routes.d.ts +4 -1
  27. package/dist/sharding/index.js +4 -1
  28. package/dist/sharding/index.js.map +4 -4
  29. package/dist/structures/base.d.ts +99 -48
  30. package/dist/structures/embed.d.ts +65 -0
  31. package/dist/structures/index.d.ts +45 -25
  32. package/dist/structures/index.js +569 -36
  33. package/dist/structures/index.js.map +10 -8
  34. package/dist/structures/interactions.d.ts +72 -17
  35. package/dist/structures/resources.d.ts +9 -5
  36. package/dist/types/index.d.ts +530 -85
  37. package/dist/types/index.js +71 -1
  38. package/dist/types/index.js.map +3 -3
  39. package/dist/voice/index.js.map +1 -1
  40. package/dist/ws/index.js +4 -1
  41. package/dist/ws/index.js.map +4 -4
  42. package/package.json +15 -15
package/dist/index.js CHANGED
@@ -420,6 +420,223 @@ class PermissionsBitField extends PermissionSet {
420
420
  super(value);
421
421
  }
422
422
  }
423
+ // packages/core/src/events.ts
424
+ var ClientEvent;
425
+ ((ClientEvent2) => {
426
+ ClientEvent2["Ready"] = "ready";
427
+ ClientEvent2["Raw"] = "raw";
428
+ ClientEvent2["Error"] = "error";
429
+ ClientEvent2["Open"] = "open";
430
+ ClientEvent2["Close"] = "close";
431
+ ClientEvent2["MessageCreate"] = "messageCreate";
432
+ ClientEvent2["MessageUpdate"] = "messageUpdate";
433
+ ClientEvent2["MessageDelete"] = "messageDelete";
434
+ ClientEvent2["MessageDeleteBulk"] = "messageDeleteBulk";
435
+ ClientEvent2["MessageReactionAdd"] = "messageReactionAdd";
436
+ ClientEvent2["MessageReactionRemove"] = "messageReactionRemove";
437
+ ClientEvent2["MessageReactionRemoveAll"] = "messageReactionRemoveAll";
438
+ ClientEvent2["MessageReactionRemoveEmoji"] = "messageReactionRemoveEmoji";
439
+ ClientEvent2["MessagePollVoteAdd"] = "messagePollVoteAdd";
440
+ ClientEvent2["MessagePollVoteRemove"] = "messagePollVoteRemove";
441
+ ClientEvent2["GuildCreate"] = "guildCreate";
442
+ ClientEvent2["GuildUpdate"] = "guildUpdate";
443
+ ClientEvent2["GuildDelete"] = "guildDelete";
444
+ ClientEvent2["GuildAvailable"] = "guildAvailable";
445
+ ClientEvent2["GuildUnavailable"] = "guildUnavailable";
446
+ ClientEvent2["GuildMemberAdd"] = "guildMemberAdd";
447
+ ClientEvent2["GuildMemberUpdate"] = "guildMemberUpdate";
448
+ ClientEvent2["GuildMemberRemove"] = "guildMemberRemove";
449
+ ClientEvent2["GuildMembersChunk"] = "guildMembersChunk";
450
+ ClientEvent2["GuildBanAdd"] = "guildBanAdd";
451
+ ClientEvent2["GuildBanRemove"] = "guildBanRemove";
452
+ ClientEvent2["GuildRoleCreate"] = "guildRoleCreate";
453
+ ClientEvent2["GuildRoleUpdate"] = "guildRoleUpdate";
454
+ ClientEvent2["GuildRoleDelete"] = "guildRoleDelete";
455
+ ClientEvent2["GuildEmojisUpdate"] = "guildEmojisUpdate";
456
+ ClientEvent2["GuildStickersUpdate"] = "guildStickersUpdate";
457
+ ClientEvent2["GuildIntegrationsUpdate"] = "guildIntegrationsUpdate";
458
+ ClientEvent2["GuildScheduledEventCreate"] = "guildScheduledEventCreate";
459
+ ClientEvent2["GuildScheduledEventUpdate"] = "guildScheduledEventUpdate";
460
+ ClientEvent2["GuildScheduledEventDelete"] = "guildScheduledEventDelete";
461
+ ClientEvent2["GuildScheduledEventUserAdd"] = "guildScheduledEventUserAdd";
462
+ ClientEvent2["GuildScheduledEventUserRemove"] = "guildScheduledEventUserRemove";
463
+ ClientEvent2["AutoModerationRuleCreate"] = "autoModerationRuleCreate";
464
+ ClientEvent2["AutoModerationRuleUpdate"] = "autoModerationRuleUpdate";
465
+ ClientEvent2["AutoModerationRuleDelete"] = "autoModerationRuleDelete";
466
+ ClientEvent2["AutoModerationActionExecution"] = "autoModerationActionExecution";
467
+ ClientEvent2["ChannelCreate"] = "channelCreate";
468
+ ClientEvent2["ChannelUpdate"] = "channelUpdate";
469
+ ClientEvent2["ChannelDelete"] = "channelDelete";
470
+ ClientEvent2["ChannelPinsUpdate"] = "channelPinsUpdate";
471
+ ClientEvent2["ThreadCreate"] = "threadCreate";
472
+ ClientEvent2["ThreadUpdate"] = "threadUpdate";
473
+ ClientEvent2["ThreadDelete"] = "threadDelete";
474
+ ClientEvent2["ThreadListSync"] = "threadListSync";
475
+ ClientEvent2["ThreadMembersUpdate"] = "threadMembersUpdate";
476
+ ClientEvent2["ThreadMemberUpdate"] = "threadMemberUpdate";
477
+ ClientEvent2["StageInstanceCreate"] = "stageInstanceCreate";
478
+ ClientEvent2["StageInstanceUpdate"] = "stageInstanceUpdate";
479
+ ClientEvent2["StageInstanceDelete"] = "stageInstanceDelete";
480
+ ClientEvent2["InviteCreate"] = "inviteCreate";
481
+ ClientEvent2["InviteDelete"] = "inviteDelete";
482
+ ClientEvent2["WebhooksUpdate"] = "webhooksUpdate";
483
+ ClientEvent2["VoiceStateUpdate"] = "voiceStateUpdate";
484
+ ClientEvent2["VoiceServerUpdate"] = "voiceServerUpdate";
485
+ ClientEvent2["PresenceUpdate"] = "presenceUpdate";
486
+ ClientEvent2["TypingStart"] = "typingStart";
487
+ ClientEvent2["InteractionCreate"] = "interactionCreate";
488
+ })(ClientEvent ||= {});
489
+ // packages/types/src/index.ts
490
+ var GatewayIntentBits = {
491
+ Guilds: 1 << 0,
492
+ GuildMembers: 1 << 1,
493
+ GuildModeration: 1 << 2,
494
+ GuildExpressions: 1 << 3,
495
+ GuildIntegrations: 1 << 4,
496
+ GuildWebhooks: 1 << 5,
497
+ GuildInvites: 1 << 6,
498
+ GuildVoiceStates: 1 << 7,
499
+ GuildPresences: 1 << 8,
500
+ GuildMessages: 1 << 9,
501
+ GuildMessageReactions: 1 << 10,
502
+ GuildMessageTyping: 1 << 11,
503
+ DirectMessages: 1 << 12,
504
+ DirectMessageReactions: 1 << 13,
505
+ DirectMessageTyping: 1 << 14,
506
+ MessageContent: 1 << 15,
507
+ GuildScheduledEvents: 1 << 16,
508
+ AutoModerationConfiguration: 1 << 20,
509
+ AutoModerationExecution: 1 << 21,
510
+ GuildMessagePolls: 1 << 24,
511
+ DirectMessagePolls: 1 << 25
512
+ };
513
+ var IntentBits = {
514
+ guild: 1 << 0,
515
+ guilds: 1 << 0,
516
+ guildMembers: 1 << 1,
517
+ guildModeration: 1 << 2,
518
+ guildBans: 1 << 2,
519
+ guildExpressions: 1 << 3,
520
+ guildEmojis: 1 << 3,
521
+ guildEmojisAndStickers: 1 << 3,
522
+ guildIntegrations: 1 << 4,
523
+ guildWebhooks: 1 << 5,
524
+ guildInvites: 1 << 6,
525
+ guildVoiceStates: 1 << 7,
526
+ guildPresences: 1 << 8,
527
+ guildMessages: 1 << 9,
528
+ guildMessage: 1 << 9,
529
+ guildMessageReactions: 1 << 10,
530
+ guildMessageTyping: 1 << 11,
531
+ directMessages: 1 << 12,
532
+ directMessageReactions: 1 << 13,
533
+ directMessageTyping: 1 << 14,
534
+ messageContent: 1 << 15,
535
+ guildScheduledEvents: 1 << 16,
536
+ autoModerationConfiguration: 1 << 20,
537
+ autoModerationExecution: 1 << 21,
538
+ guildMessagePolls: 1 << 24,
539
+ directMessagePolls: 1 << 25
540
+ };
541
+ var Intents = IntentBits;
542
+ function resolveGatewayIntents(intents) {
543
+ if (typeof intents === "number")
544
+ return intents;
545
+ if (Array.isArray(intents)) {
546
+ return intents.reduce((acc, intent) => {
547
+ return acc | resolveGatewayIntents(intent);
548
+ }, 0);
549
+ }
550
+ if (typeof intents === "string") {
551
+ if (intents in GatewayIntentBits)
552
+ return GatewayIntentBits[intents];
553
+ if (intents in IntentBits)
554
+ return IntentBits[intents];
555
+ const lower = intents.charAt(0).toLowerCase() + intents.slice(1);
556
+ if (lower in IntentBits)
557
+ return IntentBits[lower];
558
+ const num = Number(intents);
559
+ if (!Number.isNaN(num))
560
+ return num;
561
+ }
562
+ return 0;
563
+ }
564
+ var MessageFlags = {
565
+ Crossposted: 1,
566
+ IsCrosspost: 2,
567
+ SuppressEmbeds: 4,
568
+ SourceMessageDeleted: 8,
569
+ Urgent: 16,
570
+ HasThread: 32,
571
+ Ephemeral: 64,
572
+ Loading: 128,
573
+ IsComponentsV2: 32768
574
+ };
575
+ var ChannelType = {
576
+ GuildText: 0,
577
+ DM: 1,
578
+ GuildVoice: 2,
579
+ GroupDM: 3,
580
+ GuildCategory: 4,
581
+ GuildAnnouncement: 5,
582
+ AnnouncementThread: 10,
583
+ PublicThread: 11,
584
+ PrivateThread: 12,
585
+ GuildStageVoice: 13,
586
+ GuildDirectory: 14,
587
+ GuildForum: 15,
588
+ GuildMedia: 16
589
+ };
590
+ var InteractionResponseType = {
591
+ Pong: 1,
592
+ ChannelMessage: 4,
593
+ DeferredChannelMessage: 5,
594
+ DeferredMessageUpdate: 6,
595
+ MessageUpdate: 7,
596
+ Autocomplete: 8,
597
+ Modal: 9
598
+ };
599
+ var StickerFormatType = {
600
+ PNG: 1,
601
+ APNG: 2,
602
+ Lottie: 3,
603
+ GIF: 4
604
+ };
605
+ var StickerType = {
606
+ Standard: 1,
607
+ Guild: 2
608
+ };
609
+ var VerificationLevel = {
610
+ None: 0,
611
+ Low: 1,
612
+ Medium: 2,
613
+ High: 3,
614
+ VeryHigh: 4
615
+ };
616
+ var PremiumTier = {
617
+ None: 0,
618
+ Tier1: 1,
619
+ Tier2: 2,
620
+ Tier3: 3
621
+ };
622
+ var ApplicationCommandOptionType = {
623
+ SubCommand: 1,
624
+ SubCommandGroup: 2,
625
+ String: 3,
626
+ Integer: 4,
627
+ Boolean: 5,
628
+ User: 6,
629
+ Channel: 7,
630
+ Role: 8,
631
+ Mentionable: 9,
632
+ Number: 10,
633
+ Attachment: 11
634
+ };
635
+ var ApplicationCommandType = {
636
+ ChatInput: 1,
637
+ User: 2,
638
+ Message: 3
639
+ };
423
640
  // packages/collection/src/cache.ts
424
641
  class Cache {
425
642
  #entries = new Collection;
@@ -452,10 +669,19 @@ class Cache {
452
669
  this.#entries.delete(key);
453
670
  return;
454
671
  }
672
+ this.#entries.delete(key);
673
+ this.#entries.set(key, entry);
455
674
  return entry.value;
456
675
  }
457
676
  has(key) {
458
- return this.get(key) !== undefined;
677
+ const entry = this.#entries.get(key);
678
+ if (!entry)
679
+ return false;
680
+ if (entry.expiresAt > 0 && entry.expiresAt <= Date.now()) {
681
+ this.#entries.delete(key);
682
+ return false;
683
+ }
684
+ return true;
459
685
  }
460
686
  set(key, value) {
461
687
  const expiresAt = this.#ttl > 0 ? Date.now() + this.#ttl : 0;
@@ -626,6 +852,28 @@ class Collection extends Map {
626
852
  entry = [item[0], item[1]];
627
853
  return entry;
628
854
  }
855
+ union(other) {
856
+ const result = this.clone();
857
+ for (const [key, value] of other)
858
+ result.set(key, value);
859
+ return result;
860
+ }
861
+ intersection(other) {
862
+ const result = new Collection;
863
+ for (const [key, value] of this) {
864
+ if (other.has(key))
865
+ result.set(key, value);
866
+ }
867
+ return result;
868
+ }
869
+ difference(other) {
870
+ const result = new Collection;
871
+ for (const [key, value] of this) {
872
+ if (!other.has(key))
873
+ result.set(key, value);
874
+ }
875
+ return result;
876
+ }
629
877
  }
630
878
 
631
879
  // packages/managers/src/base.ts
@@ -694,11 +942,27 @@ class ResourceManager extends Manager {
694
942
  return this.upsert(resource);
695
943
  }
696
944
  }
945
+ // packages/rest/package.json
946
+ var package_default = {
947
+ name: "@lunibee/rest",
948
+ version: "0.1.6",
949
+ type: "module",
950
+ module: "./src/index.ts",
951
+ types: "./src/index.ts",
952
+ exports: {
953
+ ".": "./src/index.ts"
954
+ }
955
+ };
956
+
697
957
  // packages/rest/src/routes.ts
698
958
  var Routes = {
699
959
  user: () => "/users/@me",
700
960
  userById: (userId) => `/users/${snowflake(userId, "User ID")}`,
701
961
  guild: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}`,
962
+ guildPreview: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/preview`,
963
+ guildActiveThreads: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/threads/active`,
964
+ guildWebhooks: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/webhooks`,
965
+ guildInvites: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/invites`,
702
966
  guildChannels: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/channels`,
703
967
  guildMember: (guildId, userId) => `/guilds/${snowflake(guildId, "Guild ID")}/members/${snowflake(userId, "User ID")}`,
704
968
  guildRoles: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/roles`,
@@ -726,7 +990,6 @@ var Routes = {
726
990
  guildApplicationCommand: (applicationId, guildId, commandId) => `/applications/${snowflake(applicationId, "Application ID")}/guilds/${snowflake(guildId, "Guild ID")}/commands/${snowflake(commandId, "Command ID")}`,
727
991
  interactionCallback: (interactionId, token) => `/interactions/${snowflake(interactionId, "Interaction ID")}/${encodeURIComponent(token)}/callback`,
728
992
  interactionOriginalResponse: (applicationId, token) => `/webhooks/${snowflake(applicationId, "Application ID")}/${encodeURIComponent(token)}/messages/@original`,
729
- guildActiveThreads: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/threads/active`,
730
993
  channelPublicArchivedThreads: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/threads/archived/public`,
731
994
  channelPrivateArchivedThreads: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/threads/archived/private`,
732
995
  threadMembers: (threadId) => `/channels/${snowflake(threadId, "Thread ID")}/thread-members`,
@@ -799,6 +1062,9 @@ class RESTError extends Error {
799
1062
  this.path = options.path;
800
1063
  }
801
1064
  }
1065
+ var LIBRARY_VERSION = package_default.version;
1066
+ var LIBRARY_URL = "https://github.com/Ekretos/lunibee";
1067
+ var USER_AGENT = `DiscordBot (${LIBRARY_URL}, ${package_default.version})`;
802
1068
  function createRetryPolicy(maxRetries = 2) {
803
1069
  if (!Number.isFinite(maxRetries) || maxRetries < 0)
804
1070
  throw new TypeError("maxRetries must be a non-negative finite number.");
@@ -865,15 +1131,19 @@ class REST {
865
1131
  throw this.#abortError(path, options.signal.reason);
866
1132
  options.signal?.addEventListener("abort", onAbort, { once: true });
867
1133
  const timer = setTimeout(() => controller.abort(new DOMException("REST request timeout", "TimeoutError")), this.#timeout);
1134
+ const isFormData = typeof FormData !== "undefined" && body instanceof FormData;
1135
+ const headers = {
1136
+ ...this.#token ? { Authorization: `Bot ${this.#token}` } : {},
1137
+ "User-Agent": USER_AGENT
1138
+ };
1139
+ if (!isFormData)
1140
+ headers["Content-Type"] = "application/json";
1141
+ const fetchBody = isFormData ? body : body === undefined ? undefined : JSON.stringify(body);
868
1142
  try {
869
1143
  const response = await fetch(`${this.#baseURL}${path}`, {
870
1144
  method: normalizedMethod,
871
- headers: {
872
- ...this.#token ? { Authorization: `Bot ${this.#token}` } : {},
873
- "Content-Type": "application/json",
874
- "User-Agent": "Lunibee/0.1.0"
875
- },
876
- body: body === undefined ? undefined : JSON.stringify(body),
1145
+ headers,
1146
+ body: fetchBody,
877
1147
  signal: controller.signal
878
1148
  });
879
1149
  bucket = this.#update(response, bucket, route, bucketKey);
@@ -926,6 +1196,24 @@ class REST {
926
1196
  delete(path, options) {
927
1197
  return this.request("DELETE", path, undefined, options);
928
1198
  }
1199
+ #fileForm(payload, files) {
1200
+ const form = new FormData;
1201
+ form.append("payload_json", JSON.stringify(payload));
1202
+ for (let i = 0;i < files.length; i++) {
1203
+ const file = files[i];
1204
+ const blob = file.data instanceof Blob ? file.data : new Blob([file.data], {
1205
+ type: file.contentType ?? "application/octet-stream"
1206
+ });
1207
+ form.append(`files[${i}]`, blob, file.name);
1208
+ }
1209
+ return form;
1210
+ }
1211
+ postWithFiles(path, payload, files, options) {
1212
+ return this.request("POST", path, this.#fileForm(payload, files), options);
1213
+ }
1214
+ patchWithFiles(path, payload, files, options) {
1215
+ return this.request("PATCH", path, this.#fileForm(payload, files), options);
1216
+ }
929
1217
  async#wait(bucket, signal, path) {
930
1218
  const delay = bucket.resetAt - Date.now();
931
1219
  if (bucket.remaining <= 0 && delay > 0)
@@ -1040,6 +1328,16 @@ class BaseStructure {
1040
1328
  toString() {
1041
1329
  return this.id;
1042
1330
  }
1331
+ get createdAt() {
1332
+ return new Date(Number((BigInt(this.id) >> 22n) + 1420070400000n));
1333
+ }
1334
+ }
1335
+ var CDN_BASE = "https://cdn.discordapp.com";
1336
+ function cdnURL(path, hash, options = {}) {
1337
+ const isAnimated = hash.startsWith("a_") && !options.forceStatic;
1338
+ const ext = options.extension ?? (isAnimated ? "gif" : "png");
1339
+ const size = options.size ? `?size=${options.size}` : "";
1340
+ return `${CDN_BASE}${path}/${hash}.${ext}${size}`;
1043
1341
  }
1044
1342
 
1045
1343
  class User extends BaseStructure {
@@ -1049,6 +1347,7 @@ class User extends BaseStructure {
1049
1347
  bot;
1050
1348
  system;
1051
1349
  flags;
1350
+ discriminator;
1052
1351
  constructor(data) {
1053
1352
  super(data.id);
1054
1353
  if (!data.username)
@@ -1059,6 +1358,7 @@ class User extends BaseStructure {
1059
1358
  this.bot = data.bot ?? false;
1060
1359
  this.system = data.system ?? false;
1061
1360
  this.flags = data.public_flags ?? 0;
1361
+ this.discriminator = data.discriminator && data.discriminator !== "0" ? data.discriminator : null;
1062
1362
  }
1063
1363
  get displayName() {
1064
1364
  return this.globalName ?? this.username;
@@ -1066,21 +1366,29 @@ class User extends BaseStructure {
1066
1366
  avatarURL(options = {}) {
1067
1367
  if (!this.avatar)
1068
1368
  return null;
1069
- const extension = options.extension ?? (this.avatar.startsWith("a_") ? "gif" : "png");
1070
- return `https://cdn.discordapp.com/avatars/${this.id}/${this.avatar}.${extension}${options.size ? `?size=${options.size}` : ""}`;
1369
+ return cdnURL(`/avatars/${this.id}`, this.avatar, options);
1071
1370
  }
1072
1371
  defaultAvatarURL() {
1073
- return `https://cdn.discordapp.com/embed/avatars/${Number(BigInt(this.id) % 5n)}.png`;
1372
+ const index = this.discriminator ? Number(this.discriminator) % 5 : Number((BigInt(this.id) >> 22n) % 6n);
1373
+ return `${CDN_BASE}/embed/avatars/${index}.png`;
1074
1374
  }
1075
1375
  displayAvatarURL(options = {}) {
1076
1376
  return this.avatarURL(options) ?? this.defaultAvatarURL();
1077
1377
  }
1378
+ toString() {
1379
+ return `<@${this.id}>`;
1380
+ }
1078
1381
  }
1079
1382
 
1080
1383
  class Channel extends BaseStructure {
1081
1384
  type;
1082
1385
  name;
1083
1386
  guildId;
1387
+ topic;
1388
+ parentId;
1389
+ nsfw;
1390
+ rateLimitPerUser;
1391
+ position;
1084
1392
  #context;
1085
1393
  constructor(data, context) {
1086
1394
  super(data.id);
@@ -1089,6 +1397,11 @@ class Channel extends BaseStructure {
1089
1397
  this.type = data.type;
1090
1398
  this.name = data.name;
1091
1399
  this.guildId = data.guild_id;
1400
+ this.topic = data.topic;
1401
+ this.parentId = data.parent_id;
1402
+ this.nsfw = data.nsfw;
1403
+ this.rateLimitPerUser = data.rate_limit_per_user;
1404
+ this.position = data.position;
1092
1405
  this.#context = context;
1093
1406
  }
1094
1407
  sendMessage(options) {
@@ -1096,19 +1409,112 @@ class Channel extends BaseStructure {
1096
1409
  throw new Error("This channel is not attached to a client.");
1097
1410
  return this.#context.sendMessage(this.id, options);
1098
1411
  }
1412
+ send(options) {
1413
+ return this.sendMessage(options);
1414
+ }
1415
+ edit(options) {
1416
+ if (!this.#context?.editChannel)
1417
+ throw new Error("This channel is not attached to a client.");
1418
+ return this.#context.editChannel(this.id, options);
1419
+ }
1420
+ editName(name) {
1421
+ if (!name.trim())
1422
+ throw new TypeError("Channel name cannot be empty.");
1423
+ return this.edit({ name });
1424
+ }
1425
+ editTopic(topic) {
1426
+ return this.edit({ topic });
1427
+ }
1428
+ editParent(parentId) {
1429
+ return this.edit({ parent_id: parentId });
1430
+ }
1431
+ delete() {
1432
+ if (!this.#context?.deleteChannel)
1433
+ throw new Error("This channel is not attached to a client.");
1434
+ return this.#context.deleteChannel(this.id);
1435
+ }
1436
+ update(options) {
1437
+ return this.edit(options);
1438
+ }
1439
+ toString() {
1440
+ return `<#${this.id}>`;
1441
+ }
1099
1442
  }
1100
1443
 
1101
1444
  class Guild extends BaseStructure {
1102
1445
  name;
1446
+ icon;
1447
+ splash;
1448
+ banner;
1449
+ description;
1103
1450
  preferredLocale;
1104
1451
  ownerId;
1452
+ features;
1453
+ verificationLevel;
1454
+ premiumTier;
1455
+ premiumSubscriptionCount;
1456
+ memberCount;
1457
+ approximateMemberCount;
1458
+ approximatePresenceCount;
1459
+ vanityUrlCode;
1460
+ nsfwLevel;
1461
+ discoverySplash;
1105
1462
  constructor(data) {
1106
1463
  super(data.id);
1107
1464
  if (!data.name)
1108
1465
  throw new TypeError("A Discord guild requires a name.");
1109
1466
  this.name = data.name;
1110
- this.preferredLocale = data.preferred_locale;
1467
+ this.icon = data.icon ?? null;
1468
+ this.splash = data.splash ?? null;
1469
+ this.banner = data.banner ?? null;
1470
+ this.description = data.description ?? null;
1471
+ this.preferredLocale = data.preferred_locale ?? "en-US";
1111
1472
  this.ownerId = data.owner_id;
1473
+ this.features = data.features ?? [];
1474
+ this.verificationLevel = data.verification_level ?? 0;
1475
+ this.premiumTier = data.premium_tier ?? 0;
1476
+ this.premiumSubscriptionCount = data.premium_subscription_count ?? 0;
1477
+ this.memberCount = data.member_count ?? data.approximate_member_count;
1478
+ this.approximateMemberCount = data.approximate_member_count;
1479
+ this.approximatePresenceCount = data.approximate_presence_count;
1480
+ this.vanityUrlCode = data.vanity_url_code ?? null;
1481
+ this.nsfwLevel = data.nsfw_level ?? 0;
1482
+ this.discoverySplash = data.discovery_splash ?? null;
1483
+ }
1484
+ iconURL(options = {}) {
1485
+ if (!this.icon)
1486
+ return null;
1487
+ return cdnURL(`/icons/${this.id}`, this.icon, options);
1488
+ }
1489
+ splashURL(options = {}) {
1490
+ if (!this.splash)
1491
+ return null;
1492
+ return cdnURL(`/splashes/${this.id}`, this.splash, options);
1493
+ }
1494
+ bannerURL(options = {}) {
1495
+ if (!this.banner)
1496
+ return null;
1497
+ return cdnURL(`/banners/${this.id}`, this.banner, options);
1498
+ }
1499
+ discoverySplashURL(options = {}) {
1500
+ if (!this.discoverySplash)
1501
+ return null;
1502
+ return cdnURL(`/discovery-splashes/${this.id}`, this.discoverySplash, options);
1503
+ }
1504
+ hasFeature(feature) {
1505
+ return this.features.includes(feature);
1506
+ }
1507
+ get isCommunity() {
1508
+ return this.hasFeature("COMMUNITY");
1509
+ }
1510
+ get hasVanityUrl() {
1511
+ return this.vanityUrlCode !== null;
1512
+ }
1513
+ get vanityURL() {
1514
+ return this.vanityUrlCode ? `https://discord.gg/${this.vanityUrlCode}` : null;
1515
+ }
1516
+ toString() {
1517
+ return this.name;
1112
1518
  }
1113
1519
  }
1114
1520
  // packages/structures/src/permissions.ts
@@ -1270,6 +1676,9 @@ class GuildMember {
1270
1676
  get displayName() {
1271
1677
  return this.nickname ?? this.user.displayName;
1272
1678
  }
1679
+ toString() {
1680
+ return this.user.toString();
1681
+ }
1273
1682
  }
1274
1683
 
1275
1684
  class Role extends BaseStructure {
@@ -1296,10 +1705,8 @@ class Role extends BaseStructure {
1296
1705
  }
1297
1706
 
1298
1707
  class TextChannel extends Channel {
1299
- parentId;
1300
- constructor(data) {
1301
- super(data);
1302
- this.parentId = data.parent_id;
1708
+ constructor(data, context) {
1709
+ super(data, context);
1303
1710
  }
1304
1711
  toString() {
1305
1712
  return `<#${this.id}>`;
@@ -1313,16 +1720,167 @@ var InteractionType = {
1313
1720
  ApplicationCommandAutocomplete: 4,
1314
1721
  ModalSubmit: 5
1315
1722
  };
1316
- var InteractionResponseType = {
1317
- Pong: 1,
1318
- ChannelMessage: 4,
1319
- DeferredChannelMessage: 5,
1320
- DeferredMessageUpdate: 6,
1321
- MessageUpdate: 7,
1322
- Autocomplete: 8,
1323
- Modal: 9
1723
+ var OptionType = {
1724
+ SubCommand: 1,
1725
+ SubCommandGroup: 2,
1726
+ String: 3,
1727
+ Integer: 4,
1728
+ Boolean: 5,
1729
+ User: 6,
1730
+ Channel: 7,
1731
+ Role: 8,
1732
+ Mentionable: 9,
1733
+ Number: 10,
1734
+ Attachment: 11
1324
1735
  };
1325
1736
 
1737
+ class CommandOptions {
1738
+ #options;
1739
+ #resolved;
1740
+ constructor(options, resolved = {}) {
1741
+ let currentOptions = options;
1742
+ let group = null;
1743
+ let sub = null;
1744
+ while (currentOptions.length === 1) {
1745
+ const opt = currentOptions[0];
1746
+ if (opt.type === OptionType.SubCommandGroup) {
1747
+ group = opt.name;
1748
+ currentOptions = opt.options ?? [];
1749
+ } else if (opt.type === OptionType.SubCommand) {
1750
+ sub = opt.name;
1751
+ currentOptions = opt.options ?? [];
1752
+ } else {
1753
+ break;
1754
+ }
1755
+ }
1756
+ this.#options = currentOptions;
1757
+ this.#resolved = resolved;
1758
+ this.#subcommandGroup = group;
1759
+ this.#subcommand = sub;
1760
+ }
1761
+ #subcommandGroup;
1762
+ #subcommand;
1763
+ #get(name) {
1764
+ return this.#options.find((o) => o.name.toLowerCase() === name.toLowerCase());
1765
+ }
1766
+ getSubcommand(required = false) {
1767
+ if (!this.#subcommand && required) {
1768
+ throw new TypeError("No subcommand was provided.");
1769
+ }
1770
+ return this.#subcommand;
1771
+ }
1772
+ getSubcommandGroup(required = false) {
1773
+ if (!this.#subcommandGroup && required) {
1774
+ throw new TypeError("No subcommand group was provided.");
1775
+ }
1776
+ return this.#subcommandGroup;
1777
+ }
1778
+ getString(name, required = false) {
1779
+ const opt = this.#get(name);
1780
+ if (!opt || opt.type !== OptionType.String) {
1781
+ if (required)
1782
+ throw new TypeError(`Required option "${name}" (string) is missing.`);
1783
+ return null;
1784
+ }
1785
+ return typeof opt.value === "string" ? opt.value : null;
1786
+ }
1787
+ getInteger(name, required = false) {
1788
+ const opt = this.#get(name);
1789
+ if (!opt || opt.type !== OptionType.Integer) {
1790
+ if (required)
1791
+ throw new TypeError(`Required option "${name}" (integer) is missing.`);
1792
+ return null;
1793
+ }
1794
+ return typeof opt.value === "number" ? Math.trunc(opt.value) : null;
1795
+ }
1796
+ getNumber(name, required = false) {
1797
+ const opt = this.#get(name);
1798
+ if (!opt || opt.type !== OptionType.Number) {
1799
+ if (required)
1800
+ throw new TypeError(`Required option "${name}" (number) is missing.`);
1801
+ return null;
1802
+ }
1803
+ return typeof opt.value === "number" ? opt.value : null;
1804
+ }
1805
+ getBoolean(name, required = false) {
1806
+ const opt = this.#get(name);
1807
+ if (!opt || opt.type !== OptionType.Boolean) {
1808
+ if (required)
1809
+ throw new TypeError(`Required option "${name}" (boolean) is missing.`);
1810
+ return null;
1811
+ }
1812
+ return typeof opt.value === "boolean" ? opt.value : null;
1813
+ }
1814
+ getUser(name, required = false) {
1815
+ const opt = this.#get(name);
1816
+ if (!opt || opt.type !== OptionType.User) {
1817
+ if (required)
1818
+ throw new TypeError(`Required option "${name}" (user) is missing.`);
1819
+ return null;
1820
+ }
1821
+ const userId = String(opt.value);
1822
+ const resolved = this.#resolved?.users?.[userId] ?? null;
1823
+ if (!resolved && required)
1824
+ throw new TypeError(`Resolved user for option "${name}" is missing.`);
1825
+ return resolved;
1826
+ }
1827
+ getChannel(name, required = false) {
1828
+ const opt = this.#get(name);
1829
+ if (!opt || opt.type !== OptionType.Channel) {
1830
+ if (required)
1831
+ throw new TypeError(`Required option "${name}" (channel) is missing.`);
1832
+ return null;
1833
+ }
1834
+ const channelId = String(opt.value);
1835
+ const resolved = this.#resolved?.channels?.[channelId] ?? null;
1836
+ if (!resolved && required)
1837
+ throw new TypeError(`Resolved channel for option "${name}" is missing.`);
1838
+ return resolved;
1839
+ }
1840
+ getRole(name, required = false) {
1841
+ const opt = this.#get(name);
1842
+ if (!opt || opt.type !== OptionType.Role) {
1843
+ if (required)
1844
+ throw new TypeError(`Required option "${name}" (role) is missing.`);
1845
+ return null;
1846
+ }
1847
+ const roleId = String(opt.value);
1848
+ const resolved = this.#resolved?.roles?.[roleId] ?? null;
1849
+ if (!resolved && required)
1850
+ throw new TypeError(`Resolved role for option "${name}" is missing.`);
1851
+ return resolved;
1852
+ }
1853
+ getMentionable(name, required = false) {
1854
+ const opt = this.#get(name);
1855
+ if (!opt || opt.type !== OptionType.Mentionable) {
1856
+ if (required)
1857
+ throw new TypeError(`Required option "${name}" (mentionable) is missing.`);
1858
+ return null;
1859
+ }
1860
+ const id = String(opt.value);
1861
+ const resolved = this.#resolved?.users?.[id] ?? this.#resolved?.roles?.[id] ?? null;
1862
+ if (!resolved && required)
1863
+ throw new TypeError(`Resolved mentionable for option "${name}" is missing.`);
1864
+ return resolved;
1865
+ }
1866
+ getAttachment(name, required = false) {
1867
+ const opt = this.#get(name);
1868
+ if (!opt || opt.type !== OptionType.Attachment) {
1869
+ if (required)
1870
+ throw new TypeError(`Required option "${name}" (attachment) is missing.`);
1871
+ return null;
1872
+ }
1873
+ const attachmentId = String(opt.value);
1874
+ const resolved = this.#resolved?.attachments?.[attachmentId] ?? null;
1875
+ if (!resolved && required)
1876
+ throw new TypeError(`Resolved attachment for option "${name}" is missing.`);
1877
+ return resolved;
1878
+ }
1879
+ get raw() {
1880
+ return this.#options;
1881
+ }
1882
+ }
1883
+
1326
1884
  class InteractionResponse {
1327
1885
  type;
1328
1886
  data;
@@ -1436,9 +1994,17 @@ class Interaction {
1436
1994
  }
1437
1995
 
1438
1996
  class CommandInteraction extends Interaction {
1997
+ options;
1439
1998
  get commandName() {
1440
1999
  return typeof this.data.data?.name === "string" ? this.data.data.name : "";
1441
2000
  }
2001
+ constructor(client, data) {
2002
+ super(client, data);
2003
+ const rawOptions = data.data?.options ?? [];
2004
+ 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);
2007
+ }
1442
2008
  }
1443
2009
 
1444
2010
  class ComponentInteraction extends Interaction {
@@ -1464,18 +2030,6 @@ class ComponentInteraction extends Interaction {
1464
2030
  return result;
1465
2031
  }
1466
2032
  }
1467
- function createInteraction(client, data) {
1468
- switch (data.type) {
1469
- case InteractionType.ApplicationCommand:
1470
- case InteractionType.ApplicationCommandAutocomplete:
1471
- return new CommandInteraction(client, data);
1472
- case InteractionType.MessageComponent:
1473
- case InteractionType.ModalSubmit:
1474
- return new ComponentInteraction(client, data);
1475
- default:
1476
- return new Interaction(client, data);
1477
- }
1478
- }
1479
2033
 
1480
2034
  class ModalSubmitInteraction extends Interaction {
1481
2035
  get customId() {
@@ -1491,6 +2045,12 @@ class ModalSubmitInteraction extends Interaction {
1491
2045
  }
1492
2046
  return;
1493
2047
  }
2048
+ getRequiredInputValue(customId) {
2049
+ const value = this.getInputValue(customId);
2050
+ if (value === undefined)
2051
+ throw new TypeError(`Modal input "${customId}" was not found in the submission.`);
2052
+ return value;
2053
+ }
1494
2054
  }
1495
2055
 
1496
2056
  class AutocompleteInteraction extends Interaction {
@@ -1499,11 +2059,178 @@ class AutocompleteInteraction extends Interaction {
1499
2059
  }
1500
2060
  get focusedOption() {
1501
2061
  const options = this.data?.data?.options ?? [];
1502
- return options.find((opt) => opt.focused);
2062
+ return findFocused(options);
1503
2063
  }
1504
2064
  async respond(choices) {
2065
+ if (!Array.isArray(choices))
2066
+ throw new TypeError("Autocomplete choices must be an array.");
1505
2067
  const response = new InteractionResponse(InteractionResponseType.Autocomplete, { choices });
1506
2068
  await this.postResponse(response);
2069
+ this.replied = true;
2070
+ }
2071
+ }
2072
+ function findFocused(options) {
2073
+ for (const opt of options) {
2074
+ if (opt.focused)
2075
+ return { name: opt.name, value: opt.value, type: opt.type };
2076
+ if (Array.isArray(opt.options)) {
2077
+ const found = findFocused(opt.options);
2078
+ if (found)
2079
+ return found;
2080
+ }
2081
+ }
2082
+ return;
2083
+ }
2084
+ function createInteraction(client, data) {
2085
+ switch (data.type) {
2086
+ case InteractionType.ApplicationCommand:
2087
+ return new CommandInteraction(client, data);
2088
+ case InteractionType.ApplicationCommandAutocomplete:
2089
+ return new AutocompleteInteraction(client, data);
2090
+ case InteractionType.MessageComponent:
2091
+ return new ComponentInteraction(client, data);
2092
+ case InteractionType.ModalSubmit:
2093
+ return new ModalSubmitInteraction(client, data);
2094
+ default:
2095
+ return new Interaction(client, data);
2096
+ }
2097
+ }
2098
+ // packages/structures/src/embed.ts
2099
+ class Embed {
2100
+ #data;
2101
+ constructor(data = {}) {
2102
+ this.#data = { ...data };
2103
+ if (this.#data.fields)
2104
+ this.#data.fields = [...this.#data.fields];
2105
+ }
2106
+ get title() {
2107
+ return this.#data.title;
2108
+ }
2109
+ get description() {
2110
+ return this.#data.description;
2111
+ }
2112
+ get url() {
2113
+ return this.#data.url;
2114
+ }
2115
+ get color() {
2116
+ return this.#data.color;
2117
+ }
2118
+ get timestamp() {
2119
+ return this.#data.timestamp;
2120
+ }
2121
+ get createdAt() {
2122
+ return this.#data.timestamp ? new Date(this.#data.timestamp) : undefined;
2123
+ }
2124
+ get footer() {
2125
+ return this.#data.footer;
2126
+ }
2127
+ get image() {
2128
+ return this.#data.image;
2129
+ }
2130
+ get thumbnail() {
2131
+ return this.#data.thumbnail;
2132
+ }
2133
+ get video() {
2134
+ return this.#data.video;
2135
+ }
2136
+ get author() {
2137
+ return this.#data.author;
2138
+ }
2139
+ get fields() {
2140
+ return this.#data.fields ?? [];
2141
+ }
2142
+ setTitle(title) {
2143
+ if (title.length > 256)
2144
+ throw new TypeError("Embed title must not exceed 256 characters.");
2145
+ this.#data.title = title;
2146
+ return this;
2147
+ }
2148
+ setDescription(description) {
2149
+ if (description.length > 4096)
2150
+ throw new TypeError("Embed description must not exceed 4096 characters.");
2151
+ this.#data.description = description;
2152
+ return this;
2153
+ }
2154
+ setURL(url) {
2155
+ this.#data.url = url;
2156
+ return this;
2157
+ }
2158
+ setColor(color) {
2159
+ if (typeof color === "string") {
2160
+ const hex = color.replace(/^#/, "");
2161
+ this.#data.color = parseInt(hex, 16);
2162
+ } else {
2163
+ this.#data.color = color;
2164
+ }
2165
+ return this;
2166
+ }
2167
+ setTimestamp(timestamp = Date.now()) {
2168
+ this.#data.timestamp = new Date(timestamp).toISOString();
2169
+ return this;
2170
+ }
2171
+ setFooter(text, iconURL) {
2172
+ if (text.length > 2048)
2173
+ throw new TypeError("Embed footer text must not exceed 2048 characters.");
2174
+ this.#data.footer = iconURL ? { text, icon_url: iconURL } : { text };
2175
+ return this;
2176
+ }
2177
+ setImage(url) {
2178
+ this.#data.image = { url };
2179
+ return this;
2180
+ }
2181
+ setThumbnail(url) {
2182
+ this.#data.thumbnail = { url };
2183
+ return this;
2184
+ }
2185
+ setAuthor(name, options = {}) {
2186
+ if (name.length > 256)
2187
+ throw new TypeError("Embed author name must not exceed 256 characters.");
2188
+ this.#data.author = {
2189
+ name,
2190
+ url: options.url,
2191
+ icon_url: options.iconURL
2192
+ };
2193
+ return this;
2194
+ }
2195
+ addFields(...fields) {
2196
+ const existing = this.#data.fields ?? [];
2197
+ if (existing.length + fields.length > 25)
2198
+ throw new TypeError("Embeds cannot have more than 25 fields.");
2199
+ for (const field of fields) {
2200
+ if (field.name.length > 256)
2201
+ throw new TypeError("Embed field name must not exceed 256 characters.");
2202
+ if (field.value.length > 1024)
2203
+ throw new TypeError("Embed field value must not exceed 1024 characters.");
2204
+ }
2205
+ this.#data.fields = [...existing, ...fields];
2206
+ return this;
2207
+ }
2208
+ clearFields() {
2209
+ this.#data.fields = [];
2210
+ return this;
2211
+ }
2212
+ spliceFields(index, deleteCount, ...fields) {
2213
+ const next = [...this.#data.fields ?? []];
2214
+ next.splice(index, deleteCount, ...fields);
2215
+ if (next.length > 25)
2216
+ throw new TypeError("Embeds cannot have more than 25 fields.");
2217
+ for (const field of fields) {
2218
+ if (field.name.length > 256)
2219
+ throw new TypeError("Embed field name must not exceed 256 characters.");
2220
+ if (field.value.length > 1024)
2221
+ throw new TypeError("Embed field value must not exceed 1024 characters.");
2222
+ }
2223
+ this.#data.fields = next;
2224
+ return this;
2225
+ }
2226
+ toJSON() {
2227
+ const json = { ...this.#data };
2228
+ if (json.fields)
2229
+ json.fields = [...json.fields];
2230
+ return json;
2231
+ }
2232
+ static from(data) {
2233
+ return new Embed(data);
1507
2234
  }
1508
2235
  }
1509
2236
 
@@ -1515,7 +2242,7 @@ class Message extends BaseStructure {
1515
2242
  channel;
1516
2243
  guildId;
1517
2244
  flags;
1518
- createdAt;
2245
+ timestamp;
1519
2246
  attachments;
1520
2247
  embeds;
1521
2248
  mentions;
@@ -1524,6 +2251,7 @@ class Message extends BaseStructure {
1524
2251
  mentionEveryone;
1525
2252
  type;
1526
2253
  reference;
2254
+ components;
1527
2255
  referencedMessage;
1528
2256
  #context;
1529
2257
  constructor(data, context) {
@@ -1535,9 +2263,10 @@ class Message extends BaseStructure {
1535
2263
  this.channelId = data.channel_id;
1536
2264
  this.guildId = data.guild_id;
1537
2265
  this.flags = data.flags ?? 0;
1538
- this.createdAt = new Date(data.timestamp ?? Number((BigInt(this.id) >> 22n) + 1420070400000n));
2266
+ this.timestamp = new Date(data.timestamp ?? Number((BigInt(this.id) >> 22n) + 1420070400000n));
1539
2267
  this.attachments = data.attachments ?? [];
1540
2268
  this.embeds = data.embeds ?? [];
2269
+ this.components = data.components ?? [];
1541
2270
  this.mentions = (data.mentions ?? []).map((user) => new User(user));
1542
2271
  this.mentionRoles = data.mention_roles ?? [];
1543
2272
  this.pinned = data.pinned ?? false;
@@ -1556,16 +2285,14 @@ class Message extends BaseStructure {
1556
2285
  throw new Error("This message is not attached to a client.");
1557
2286
  return this.#context.editMessage(this.channelId, this.id, options);
1558
2287
  }
2288
+ update(options) {
2289
+ return this.edit(options);
2290
+ }
1559
2291
  delete() {
1560
2292
  if (!this.#context)
1561
2293
  throw new Error("This message is not attached to a client.");
1562
2294
  return this.#context.deleteMessage(this.channelId, this.id);
1563
2295
  }
1564
- crosspost() {
1565
- if (!this.#context)
1566
- throw new Error("This message is not attached to a client.");
1567
- return this.#context.crosspostMessage(this.channelId, this.id);
1568
- }
1569
2296
  reply(options) {
1570
2297
  if (!this.#context)
1571
2298
  throw new Error("This message is not attached to a client.");
@@ -1577,6 +2304,36 @@ class Message extends BaseStructure {
1577
2304
  };
1578
2305
  return this.#context.sendMessage(this.channelId, payload);
1579
2306
  }
2307
+ crosspost() {
2308
+ if (!this.#context)
2309
+ throw new Error("This message is not attached to a client.");
2310
+ return this.#context.crosspostMessage(this.channelId, this.id);
2311
+ }
2312
+ react(emoji) {
2313
+ if (!this.#context?.addReaction)
2314
+ throw new Error("This message is not attached to a client.");
2315
+ return this.#context.addReaction(this.channelId, this.id, emoji);
2316
+ }
2317
+ removeReaction(emoji, userId) {
2318
+ if (!this.#context)
2319
+ throw new Error("This message is not attached to a client.");
2320
+ return userId ? this.#context.removeReaction?.(this.channelId, this.id, emoji, userId) ?? Promise.reject(new Error("Reaction operations are unavailable.")) : this.#context.removeOwnReaction?.(this.channelId, this.id, emoji) ?? Promise.reject(new Error("Reaction operations are unavailable."));
2321
+ }
2322
+ removeAllReactions() {
2323
+ if (!this.#context?.removeAllReactions)
2324
+ throw new Error("This message is not attached to a client.");
2325
+ return this.#context.removeAllReactions(this.channelId, this.id);
2326
+ }
2327
+ pin() {
2328
+ if (!this.#context?.pinMessage)
2329
+ throw new Error("This message is not attached to a client.");
2330
+ return this.#context.pinMessage(this.channelId, this.id);
2331
+ }
2332
+ unpin() {
2333
+ if (!this.#context?.unpinMessage)
2334
+ throw new Error("This message is not attached to a client.");
2335
+ return this.#context.unpinMessage(this.channelId, this.id);
2336
+ }
1580
2337
  }
1581
2338
 
1582
2339
  // packages/managers/src/message.ts
@@ -1601,10 +2358,7 @@ class MessageManager {
1601
2358
  }
1602
2359
  async fetch(messageId) {
1603
2360
  const data = await this.#rest.get(Routes.message(this.#channelId, messageId));
1604
- const message = Array.isArray(data) ? data[0] : data;
1605
- if (!message)
1606
- throw new Error("Discord returned no message payload.");
1607
- return this.upsert(message);
2361
+ return this.upsert(data);
1608
2362
  }
1609
2363
  fetchMany(messageIds) {
1610
2364
  return Promise.all(Array.from(messageIds, (messageId) => this.fetch(messageId)));
@@ -1645,6 +2399,62 @@ class ThreadManager {
1645
2399
  return new Channel(data, this.#context);
1646
2400
  }
1647
2401
  }
2402
+
2403
+ // packages/managers/src/user.ts
2404
+ class UserManager extends ResourceManager {
2405
+ #rest;
2406
+ constructor(rest) {
2407
+ super(async (id) => new User(await rest.get(Routes.userById(id))), (user) => user.id);
2408
+ this.#rest = rest;
2409
+ }
2410
+ async fetchMe() {
2411
+ const data = await this.#rest.get("/users/@me");
2412
+ return this.upsert(new User(data));
2413
+ }
2414
+ async editMe(options) {
2415
+ const data = await this.#rest.patch("/users/@me", options);
2416
+ return this.upsert(new User(data));
2417
+ }
2418
+ async leaveGuild(guildId) {
2419
+ await this.#rest.delete(`/users/@me/guilds/${guildId}`);
2420
+ }
2421
+ async createDM(userId) {
2422
+ return this.#rest.post("/users/@me/channels", {
2423
+ recipient_id: userId
2424
+ });
2425
+ }
2426
+ }
2427
+ // packages/managers/src/guild.ts
2428
+ class GuildManager extends ResourceManager {
2429
+ #rest;
2430
+ constructor(rest) {
2431
+ super(async (id) => new Guild(await rest.get(Routes.guild(id))), (guild) => guild.id);
2432
+ this.#rest = rest;
2433
+ }
2434
+ async create(options) {
2435
+ const data = await this.#rest.post("/guilds", options);
2436
+ return this.upsert(new Guild(data));
2437
+ }
2438
+ async edit(id, options) {
2439
+ const data = await this.#rest.patch(Routes.guild(id), options);
2440
+ return this.upsert(new Guild(data));
2441
+ }
2442
+ async deleteGuild(id) {
2443
+ await this.#rest.delete(Routes.guild(id));
2444
+ }
2445
+ async fetchPreview(id) {
2446
+ return this.#rest.get(Routes.guildPreview(id));
2447
+ }
2448
+ async fetchActiveThreads(id) {
2449
+ return this.#rest.get(Routes.guildActiveThreads(id));
2450
+ }
2451
+ async fetchWebhooks(id) {
2452
+ return this.#rest.get(Routes.guildWebhooks(id));
2453
+ }
2454
+ async fetchInvites(id) {
2455
+ return this.#rest.get(Routes.guildInvites(id));
2456
+ }
2457
+ }
1648
2458
  // packages/managers/src/role.ts
1649
2459
  class RoleManager extends ResourceManager {
1650
2460
  #rest;
@@ -1767,23 +2577,6 @@ class ApplicationCommandManager {
1767
2577
  }
1768
2578
 
1769
2579
  // packages/managers/src/index.ts
1770
- class UserManager extends ResourceManager {
1771
- constructor(rest) {
1772
- super(async (id) => new User(await rest.get(Routes.userById(id))), (user) => user.id);
1773
- }
1774
- }
1775
-
1776
- class GuildManager extends ResourceManager {
1777
- constructor(rest) {
1778
- super(async (id) => new Guild(await rest.get(Routes.guild(id))), (guild) => guild.id);
1779
- }
1780
- }
1781
- var MessageCreateOptions = undefined;
1782
- var MessageEditOptions = undefined;
1783
- var MessageFetchOptions = undefined;
1784
- var MessageThreadOptions = undefined;
1785
- var ReactionFetchOptions = undefined;
1786
-
1787
2580
  class ChannelManager extends Manager {
1788
2581
  #rest;
1789
2582
  #context;
@@ -1795,7 +2588,15 @@ class ChannelManager extends Manager {
1795
2588
  sendMessage: (channelId, options) => this.send(channelId, options),
1796
2589
  editMessage: (channelId, messageId, options) => this.editMessage(channelId, messageId, options),
1797
2590
  deleteMessage: (channelId, messageId) => this.deleteMessage(channelId, messageId),
1798
- crosspostMessage: (channelId, messageId) => this.crosspostMessage(channelId, messageId)
2591
+ crosspostMessage: (channelId, messageId) => this.crosspostMessage(channelId, messageId),
2592
+ editChannel: (channelId, options) => this.edit(channelId, options),
2593
+ deleteChannel: (channelId) => this.deleteChannel(channelId),
2594
+ addReaction: (channelId, messageId, emoji) => this.addReaction(channelId, messageId, emoji),
2595
+ removeOwnReaction: (channelId, messageId, emoji) => this.removeOwnReaction(channelId, messageId, emoji),
2596
+ removeReaction: (channelId, messageId, emoji, userId) => this.removeReaction(channelId, messageId, emoji, userId),
2597
+ removeAllReactions: (channelId, messageId) => this.removeAllReactions(channelId, messageId),
2598
+ pinMessage: (channelId, messageId) => this.pinMessage(channelId, messageId),
2599
+ unpinMessage: (channelId, messageId) => this.unpinMessage(channelId, messageId)
1799
2600
  };
1800
2601
  }
1801
2602
  messages(channelId) {
@@ -1810,8 +2611,7 @@ class ChannelManager extends Manager {
1810
2611
  return new ThreadManager(this.#rest, this.#context, channelId);
1811
2612
  }
1812
2613
  async fetch(channelId) {
1813
- const data = await this.#rest.get(Routes.channel(channelId));
1814
- return this.upsert(data);
2614
+ return this.upsert(await this.#rest.get(Routes.channel(channelId)));
1815
2615
  }
1816
2616
  async resolve(channelId) {
1817
2617
  return this.get(channelId) ?? this.fetch(channelId);
@@ -1829,6 +2629,17 @@ class ChannelManager extends Manager {
1829
2629
  update(channel) {
1830
2630
  return this.set(channel.id, channel);
1831
2631
  }
2632
+ async create(guildId, options) {
2633
+ return this.upsert(await this.#rest.post(Routes.guildChannels(guildId), options));
2634
+ }
2635
+ async edit(channelId, options) {
2636
+ return this.upsert(await this.#rest.patch(Routes.channel(channelId), options));
2637
+ }
2638
+ async deleteChannel(channelId) {
2639
+ await this.#rest.delete(Routes.channel(channelId));
2640
+ this.#messageManagers.delete(channelId);
2641
+ super.delete(channelId);
2642
+ }
1832
2643
  send(channelId, options) {
1833
2644
  return this.messages(channelId).send(options);
1834
2645
  }
@@ -1858,8 +2669,7 @@ class ChannelManager extends Manager {
1858
2669
  return this.messages(data.channel_id).upsert(data);
1859
2670
  }
1860
2671
  async editMessage(channelId, messageId, options) {
1861
- const data = await this.#rest.patch(Routes.message(channelId, messageId), options);
1862
- return this.messages(channelId).upsert(data);
2672
+ return this.messages(channelId).upsert(await this.#rest.patch(Routes.message(channelId, messageId), options));
1863
2673
  }
1864
2674
  async deleteMessage(channelId, messageId) {
1865
2675
  await this.#rest.delete(Routes.message(channelId, messageId));
@@ -1869,8 +2679,7 @@ class ChannelManager extends Manager {
1869
2679
  return this.messages(channelId).delete(messageId);
1870
2680
  }
1871
2681
  async crosspostMessage(channelId, messageId) {
1872
- const data = await this.#rest.post(Routes.crosspostMessage(channelId, messageId));
1873
- return this.messages(channelId).upsert(data);
2682
+ return this.messages(channelId).upsert(await this.#rest.post(Routes.crosspostMessage(channelId, messageId)));
1874
2683
  }
1875
2684
  async bulkDeleteMessages(channelId, messageIds) {
1876
2685
  const ids = [...messageIds];
@@ -1894,7 +2703,7 @@ class ChannelManager extends Manager {
1894
2703
  return data.map((user) => new User(user));
1895
2704
  }
1896
2705
  async removeOwnReaction(channelId, messageId, emoji) {
1897
- await this.#rest.delete(Routes.messageReactions(channelId, messageId, emoji) + "/@me");
2706
+ await this.#rest.delete(`${Routes.messageReactions(channelId, messageId, emoji)}/@me`);
1898
2707
  }
1899
2708
  async removeReaction(channelId, messageId, emoji, userId) {
1900
2709
  await this.#rest.delete(`${Routes.messageReactions(channelId, messageId, emoji)}/${userId}`);
@@ -1928,146 +2737,39 @@ function isMessageQuery(value) {
1928
2737
  return typeof value === "object" && value !== null && !(Symbol.iterator in value);
1929
2738
  }
1930
2739
 
1931
- // packages/types/src/index.ts
1932
- var GatewayIntentBits = {
1933
- Guilds: 1 << 0,
1934
- GuildMembers: 1 << 1,
1935
- GuildModeration: 1 << 2,
1936
- GuildExpressions: 1 << 3,
1937
- GuildIntegrations: 1 << 4,
1938
- GuildWebhooks: 1 << 5,
1939
- GuildInvites: 1 << 6,
1940
- GuildVoiceStates: 1 << 7,
1941
- GuildPresences: 1 << 8,
1942
- GuildMessages: 1 << 9,
1943
- GuildMessageReactions: 1 << 10,
1944
- GuildMessageTyping: 1 << 11,
1945
- DirectMessages: 1 << 12,
1946
- DirectMessageReactions: 1 << 13,
1947
- DirectMessageTyping: 1 << 14,
1948
- MessageContent: 1 << 15,
1949
- GuildScheduledEvents: 1 << 16,
1950
- AutoModerationConfiguration: 1 << 20,
1951
- AutoModerationExecution: 1 << 21,
1952
- GuildMessagePolls: 1 << 24,
1953
- DirectMessagePolls: 1 << 25
1954
- };
1955
- var IntentBits = {
1956
- guild: 1 << 0,
1957
- guilds: 1 << 0,
1958
- guildMembers: 1 << 1,
1959
- guildModeration: 1 << 2,
1960
- guildBans: 1 << 2,
1961
- guildExpressions: 1 << 3,
1962
- guildEmojis: 1 << 3,
1963
- guildEmojisAndStickers: 1 << 3,
1964
- guildIntegrations: 1 << 4,
1965
- guildWebhooks: 1 << 5,
1966
- guildInvites: 1 << 6,
1967
- guildVoiceStates: 1 << 7,
1968
- guildPresences: 1 << 8,
1969
- guildMessages: 1 << 9,
1970
- guildMessage: 1 << 9,
1971
- guildMessageReactions: 1 << 10,
1972
- guildMessageTyping: 1 << 11,
1973
- directMessages: 1 << 12,
1974
- directMessageReactions: 1 << 13,
1975
- directMessageTyping: 1 << 14,
1976
- messageContent: 1 << 15,
1977
- guildScheduledEvents: 1 << 16,
1978
- autoModerationConfiguration: 1 << 20,
1979
- autoModerationExecution: 1 << 21,
1980
- guildMessagePolls: 1 << 24,
1981
- directMessagePolls: 1 << 25
2740
+ // packages/ws/src/index.ts
2741
+ var GatewayOpcodes = {
2742
+ Dispatch: 0,
2743
+ Heartbeat: 1,
2744
+ Identify: 2,
2745
+ PresenceUpdate: 3,
2746
+ VoiceStateUpdate: 4,
2747
+ Resume: 6,
2748
+ Reconnect: 7,
2749
+ RequestGuildMembers: 8,
2750
+ InvalidSession: 9,
2751
+ Hello: 10,
2752
+ HeartbeatAck: 11
1982
2753
  };
1983
- var Intents = IntentBits;
1984
- function resolveGatewayIntents(intents) {
1985
- if (typeof intents === "number")
1986
- return intents;
1987
- if (Array.isArray(intents)) {
1988
- return intents.reduce((acc, intent) => {
1989
- return acc | resolveGatewayIntents(intent);
1990
- }, 0);
1991
- }
1992
- if (typeof intents === "string") {
1993
- if (intents in GatewayIntentBits)
1994
- return GatewayIntentBits[intents];
1995
- if (intents in IntentBits)
1996
- return IntentBits[intents];
1997
- const lower = intents.charAt(0).toLowerCase() + intents.slice(1);
1998
- if (lower in IntentBits)
1999
- return IntentBits[lower];
2000
- const num = Number(intents);
2001
- if (!Number.isNaN(num))
2002
- return num;
2003
- }
2004
- return 0;
2005
- }
2006
- var MessageFlags = {
2007
- Crossposted: 1,
2008
- IsCrosspost: 2,
2009
- SuppressEmbeds: 4,
2010
- SourceMessageDeleted: 8,
2011
- Urgent: 16,
2012
- HasThread: 32,
2013
- Ephemeral: 64,
2014
- Loading: 128,
2015
- IsComponentsV2: 32768
2016
- };
2017
- var ChannelType = {
2018
- GuildText: 0,
2019
- DM: 1,
2020
- GuildVoice: 2,
2021
- GroupDM: 3,
2022
- GuildCategory: 4,
2023
- GuildAnnouncement: 5,
2024
- AnnouncementThread: 10,
2025
- PublicThread: 11,
2026
- PrivateThread: 12,
2027
- GuildStageVoice: 13,
2028
- GuildDirectory: 14,
2029
- GuildForum: 15,
2030
- GuildMedia: 16
2031
- };
2032
- var ApplicationCommandType = {
2033
- ChatInput: 1,
2034
- User: 2,
2035
- Message: 3
2036
- };
2037
-
2038
- // packages/ws/src/index.ts
2039
- var GatewayOpcodes = {
2040
- Dispatch: 0,
2041
- Heartbeat: 1,
2042
- Identify: 2,
2043
- PresenceUpdate: 3,
2044
- VoiceStateUpdate: 4,
2045
- Resume: 6,
2046
- Reconnect: 7,
2047
- RequestGuildMembers: 8,
2048
- InvalidSession: 9,
2049
- Hello: 10,
2050
- HeartbeatAck: 11
2051
- };
2052
- var GatewayState;
2053
- ((GatewayState2) => {
2054
- GatewayState2["Connect"] = "CONNECT";
2055
- GatewayState2["Hello"] = "HELLO";
2056
- GatewayState2["Identify"] = "IDENTIFY";
2057
- GatewayState2["Resume"] = "RESUME";
2058
- GatewayState2["Ready"] = "READY";
2059
- GatewayState2["Dispatch"] = "DISPATCH";
2060
- GatewayState2["Heartbeat"] = "HEARTBEAT";
2061
- GatewayState2["Reconnect"] = "RECONNECT";
2062
- GatewayState2["Closed"] = "CLOSED";
2063
- })(GatewayState ||= {});
2064
-
2065
- class GatewayError extends Error {
2066
- code;
2067
- constructor(message, code, options) {
2068
- super(message, options);
2069
- this.name = "GatewayError";
2070
- this.code = code;
2754
+ var GatewayState;
2755
+ ((GatewayState2) => {
2756
+ GatewayState2["Connect"] = "CONNECT";
2757
+ GatewayState2["Hello"] = "HELLO";
2758
+ GatewayState2["Identify"] = "IDENTIFY";
2759
+ GatewayState2["Resume"] = "RESUME";
2760
+ GatewayState2["Ready"] = "READY";
2761
+ GatewayState2["Dispatch"] = "DISPATCH";
2762
+ GatewayState2["Heartbeat"] = "HEARTBEAT";
2763
+ GatewayState2["Reconnect"] = "RECONNECT";
2764
+ GatewayState2["Closed"] = "CLOSED";
2765
+ })(GatewayState ||= {});
2766
+
2767
+ class GatewayError extends Error {
2768
+ code;
2769
+ constructor(message, code, options) {
2770
+ super(message, options);
2771
+ this.name = "GatewayError";
2772
+ this.code = code;
2071
2773
  }
2072
2774
  }
2073
2775
 
@@ -2331,6 +3033,9 @@ class Gateway {
2331
3033
  this.#setState("READY" /* Ready */);
2332
3034
  this.#emit("ready", data);
2333
3035
  }
3036
+ this.#emit("RAW", { event: event ?? "UNKNOWN", data });
3037
+ if (this.#closed)
3038
+ return;
2334
3039
  this.#emit(event ?? "dispatch", data);
2335
3040
  }
2336
3041
  #handleHello(data) {
@@ -2533,143 +3238,839 @@ class Gateway {
2533
3238
  this.#emit("stateChange", { previous, next });
2534
3239
  }
2535
3240
  }
2536
- // packages/builders/src/embed.ts
2537
- class EmbedBuilder {
2538
- #data = {};
2539
- setTitle(value) {
2540
- this.#data.title = validate(value, 256, "Embed title");
2541
- return this;
2542
- }
2543
- setDescription(value) {
2544
- this.#data.description = validate(value, 4096, "Embed description");
2545
- return this;
2546
- }
2547
- setURL(value) {
2548
- this.#data.url = url(value, "Embed URL");
2549
- return this;
2550
- }
2551
- setColor(value) {
2552
- if (!Number.isInteger(value) || value < 0 || value > 16777215)
2553
- throw new RangeError("Embed color must be an integer between 0 and 16777215.");
2554
- this.#data.color = value;
2555
- return this;
2556
- }
2557
- setTimestamp(value = new Date) {
2558
- const date = value instanceof Date ? value : new Date(value);
2559
- if (Number.isNaN(date.getTime()))
2560
- throw new RangeError("Embed timestamp must be a valid date.");
2561
- this.#data.timestamp = date.toISOString();
2562
- return this;
2563
- }
2564
- setFooter(value) {
2565
- this.#data.footer = {
2566
- text: validate(value.text, 2048, "Footer text"),
2567
- ...value.icon_url ? { icon_url: url(value.icon_url, "Footer icon URL") } : {}
2568
- };
3241
+
3242
+ // packages/core/src/index.ts
3243
+ class EventEmitter {
3244
+ #listeners = new Map;
3245
+ on(event, listener) {
3246
+ if (typeof listener !== "function")
3247
+ throw new TypeError("Event listener must be a function.");
3248
+ let listeners = this.#listeners.get(event);
3249
+ if (!listeners)
3250
+ this.#listeners.set(event, listeners = new Set);
3251
+ listeners.add(listener);
2569
3252
  return this;
2570
3253
  }
2571
- setAuthor(value) {
2572
- this.#data.author = {
2573
- name: validate(value.name, 256, "Author name"),
2574
- ...value.url ? { url: url(value.url, "Author URL") } : {},
2575
- ...value.icon_url ? { icon_url: url(value.icon_url, "Author icon URL") } : {}
3254
+ once(event, listener) {
3255
+ const wrapped = (...args) => {
3256
+ this.off(event, wrapped);
3257
+ return listener(...args);
2576
3258
  };
2577
- return this;
3259
+ return this.on(event, wrapped);
2578
3260
  }
2579
- setThumbnail(value) {
2580
- const valueURL = typeof value === "string" ? value : value.url;
2581
- this.#data.thumbnail = { url: url(valueURL, "Thumbnail URL") };
3261
+ off(event, listener) {
3262
+ this.#listeners.get(event)?.delete(listener);
2582
3263
  return this;
2583
3264
  }
2584
- setImage(value) {
2585
- const valueURL = typeof value === "string" ? value : value.url;
2586
- this.#data.image = { url: url(valueURL, "Image URL") };
3265
+ removeAllListeners(event) {
3266
+ if (event === undefined)
3267
+ this.#listeners.clear();
3268
+ else
3269
+ this.#listeners.delete(event);
2587
3270
  return this;
2588
3271
  }
2589
- addFields(...fields) {
2590
- if (!fields.length)
2591
- throw new TypeError("At least one embed field is required.");
2592
- const current = this.#data.fields ?? [];
2593
- if (current.length + fields.length > 25)
2594
- throw new RangeError("An embed cannot contain more than 25 fields.");
2595
- for (const field of fields) {
2596
- validate(field.name, 256, "Embed field name");
2597
- validate(field.value, 1024, "Embed field value");
3272
+ emit(event, ...args) {
3273
+ const listeners = this.#listeners.get(event);
3274
+ if (!listeners?.size)
3275
+ return false;
3276
+ for (const listener of [...listeners]) {
3277
+ try {
3278
+ const result = listener(...args);
3279
+ if (result && typeof result.then === "function")
3280
+ Promise.resolve(result).catch((error) => this.#handleError(event, error));
3281
+ } catch (error) {
3282
+ this.#handleError(event, error);
3283
+ }
2598
3284
  }
2599
- this.#data.fields = [...current, ...fields.map((field) => ({ ...field }))];
2600
- return this;
2601
- }
2602
- setFields(fields) {
2603
- this.#data.fields = [];
2604
- return this.addFields(...fields);
2605
- }
2606
- spliceFields(index, deleteCount, ...fields) {
2607
- const current = [...this.#data.fields ?? []];
2608
- if (!Number.isInteger(index) || !Number.isInteger(deleteCount) || index < 0 || deleteCount < 0)
2609
- throw new RangeError("Field index and delete count must be non-negative integers.");
2610
- current.splice(index, deleteCount, ...fields);
2611
- if (current.length > 25)
2612
- throw new RangeError("An embed cannot contain more than 25 fields.");
2613
- this.#data.fields = current;
2614
- return this;
3285
+ return true;
2615
3286
  }
2616
- clearFields() {
2617
- delete this.#data.fields;
2618
- return this;
3287
+ #handleError(event, error) {
3288
+ if (event === "error" /* Error */)
3289
+ return;
3290
+ const normalized = error instanceof Error ? error : new Error(String(error), { cause: error });
3291
+ for (const listener of [
3292
+ ...this.#listeners.get("error" /* Error */) ?? []
3293
+ ]) {
3294
+ try {
3295
+ listener(normalized);
3296
+ } catch {}
3297
+ }
2619
3298
  }
2620
- clearTitle() {
2621
- delete this.#data.title;
2622
- return this;
3299
+ }
3300
+
3301
+ class Client extends EventEmitter {
3302
+ options;
3303
+ rest;
3304
+ users;
3305
+ guilds;
3306
+ channels;
3307
+ application;
3308
+ get ws() {
3309
+ return this.#gateway;
2623
3310
  }
2624
- clearDescription() {
2625
- delete this.#data.description;
2626
- return this;
3311
+ get gateway() {
3312
+ return this.#gateway;
2627
3313
  }
2628
- get data() {
2629
- return this.toJSON();
3314
+ user;
3315
+ readyAt;
3316
+ state = "idle";
3317
+ get uptime() {
3318
+ return this.readyAt ? Date.now() - this.readyAt.getTime() : null;
2630
3319
  }
2631
- toJSON() {
2632
- return structuredClone(this.#data);
3320
+ isReady() {
3321
+ return this.state === "ready";
2633
3322
  }
2634
- }
2635
- function validate(value, max, field) {
2636
- if (typeof value !== "string" || value.length === 0 || value.length > max)
2637
- throw new RangeError(`${field} must contain 1-${max} characters.`);
2638
- return value;
2639
- }
2640
- function url(value, field) {
2641
- try {
2642
- return new URL(value).toString();
2643
- } catch (error) {
2644
- throw new TypeError(`${field} must be a valid URL.`, { cause: error });
3323
+ setPresence(data) {
3324
+ return this.#gateway.setPresence?.(data) ?? false;
2645
3325
  }
2646
- }
2647
- // packages/builders/src/components.ts
2648
- var ComponentType = {
2649
- ActionRow: 1,
2650
- Button: 2,
2651
- StringSelect: 3,
2652
- TextInput: 4,
2653
- UserSelect: 5,
2654
- RoleSelect: 6,
2655
- MentionableSelect: 7,
2656
- ChannelSelect: 8
2657
- };
2658
- var ButtonStyle = {
2659
- Primary: 1,
2660
- Secondary: 2,
2661
- Success: 3,
2662
- Danger: 4,
2663
- Link: 5
2664
- };
2665
- var TextInputStyle = { Short: 1, Paragraph: 2 };
2666
-
2667
- class ActionRowBuilder {
2668
- #components = [];
2669
- addComponents(...components) {
2670
- if (!components.length)
2671
- throw new TypeError("At least one component is required.");
2672
- if (this.#components.length + components.length > 5)
3326
+ #gateway;
3327
+ #resourceContext;
3328
+ constructor(options) {
3329
+ super();
3330
+ this.options = options;
3331
+ if (!options.token?.trim())
3332
+ throw new TypeError("Client token is required.");
3333
+ this.rest = new REST({ token: options.token, ...options.rest });
3334
+ this.users = new UserManager(this.rest);
3335
+ this.guilds = new GuildManager(this.rest);
3336
+ this.channels = new ChannelManager(this.rest);
3337
+ const placeholderAppCommands = new ApplicationCommandManager(this.rest, "0");
3338
+ this.application = { commands: placeholderAppCommands };
3339
+ this.#resourceContext = {
3340
+ sendMessage: (channelId, options2) => this.channels.send(channelId, options2),
3341
+ editMessage: (channelId, messageId, options2) => this.channels.editMessage(channelId, messageId, options2),
3342
+ deleteMessage: (channelId, messageId) => this.channels.deleteMessage(channelId, messageId),
3343
+ crosspostMessage: (channelId, messageId) => this.channels.crosspostMessage(channelId, messageId),
3344
+ editChannel: (channelId, options2) => this.channels.edit(channelId, options2),
3345
+ deleteChannel: (channelId) => this.channels.deleteChannel(channelId),
3346
+ addReaction: (channelId, messageId, emoji) => this.channels.addReaction(channelId, messageId, emoji),
3347
+ removeOwnReaction: (channelId, messageId, emoji) => this.channels.removeOwnReaction(channelId, messageId, emoji),
3348
+ removeReaction: (channelId, messageId, emoji, userId) => this.channels.removeReaction(channelId, messageId, emoji, userId),
3349
+ removeAllReactions: (channelId, messageId) => this.channels.removeAllReactions(channelId, messageId),
3350
+ pinMessage: (channelId, messageId) => this.channels.pinMessage(channelId, messageId),
3351
+ unpinMessage: (channelId, messageId) => this.channels.unpinMessage(channelId, messageId)
3352
+ };
3353
+ this.#gateway = new Gateway({
3354
+ token: options.token,
3355
+ intents: options.intents,
3356
+ ...options.gateway
3357
+ });
3358
+ this.#gateway.on("READY", (data) => {
3359
+ const ready = data;
3360
+ this.user = ready.user;
3361
+ this.users.set(this.user.id, new User(this.user));
3362
+ this.readyAt = new Date;
3363
+ this.state = "ready";
3364
+ const appId = ready.application?.id ?? this.user.id;
3365
+ this.application.commands = new ApplicationCommandManager(this.rest, appId);
3366
+ this.emit("ready" /* Ready */, this.user);
3367
+ });
3368
+ this.#gateway.on("open", () => this.emit("open" /* Open */));
3369
+ this.#gateway.on("close", (data) => {
3370
+ if (this.state !== "destroyed")
3371
+ this.state = "idle";
3372
+ this.emit("close" /* Close */, data);
3373
+ });
3374
+ this.#gateway.on("MESSAGE_CREATE", (data) => {
3375
+ const message = new Message(data, this.#resourceContext);
3376
+ this.channels.set(message.channelId, message.channel);
3377
+ this.users.set(message.author.id, message.author);
3378
+ this.emit("messageCreate" /* MessageCreate */, message);
3379
+ });
3380
+ this.#gateway.on("MESSAGE_UPDATE", (data) => {
3381
+ const message = new Message(data, this.#resourceContext);
3382
+ this.channels.set(message.channelId, message.channel);
3383
+ this.users.set(message.author.id, message.author);
3384
+ this.emit("messageUpdate" /* MessageUpdate */, message);
3385
+ });
3386
+ this.#gateway.on("MESSAGE_DELETE", (data) => this.emit("messageDelete" /* MessageDelete */, data));
3387
+ this.#gateway.on("MESSAGE_DELETE_BULK", (data) => this.emit("messageDeleteBulk" /* MessageDeleteBulk */, data));
3388
+ this.#gateway.on("MESSAGE_REACTION_ADD", (data) => this.emit("messageReactionAdd" /* MessageReactionAdd */, data));
3389
+ this.#gateway.on("MESSAGE_REACTION_REMOVE", (data) => this.emit("messageReactionRemove" /* MessageReactionRemove */, data));
3390
+ this.#gateway.on("MESSAGE_REACTION_REMOVE_ALL", (data) => this.emit("messageReactionRemoveAll" /* MessageReactionRemoveAll */, data));
3391
+ this.#gateway.on("MESSAGE_REACTION_REMOVE_EMOJI", (data) => this.emit("messageReactionRemoveEmoji" /* MessageReactionRemoveEmoji */, data));
3392
+ this.#gateway.on("MESSAGE_POLL_VOTE_ADD", (data) => this.emit("messagePollVoteAdd" /* MessagePollVoteAdd */, data));
3393
+ this.#gateway.on("MESSAGE_POLL_VOTE_REMOVE", (data) => this.emit("messagePollVoteRemove" /* MessagePollVoteRemove */, data));
3394
+ this.#gateway.on("GUILD_CREATE", (data) => {
3395
+ const payload = data;
3396
+ if (payload.unavailable) {
3397
+ this.emit("guildUnavailable" /* GuildUnavailable */, payload);
3398
+ return;
3399
+ }
3400
+ const guild = new Guild(payload);
3401
+ this.guilds.set(guild.id, guild);
3402
+ for (const member of payload.members ?? [])
3403
+ this.users.set(member.user.id, new User(member.user));
3404
+ for (const channelData of [
3405
+ ...payload.channels ?? [],
3406
+ ...payload.threads ?? []
3407
+ ])
3408
+ this.channels.set(channelData.id, new Channel(channelData, this.#resourceContext));
3409
+ this.emit("guildCreate" /* GuildCreate */, payload);
3410
+ });
3411
+ this.#gateway.on("GUILD_UPDATE", (data) => {
3412
+ const guild = new Guild(data);
3413
+ this.guilds.update(guild);
3414
+ this.emit("guildUpdate" /* GuildUpdate */, data);
3415
+ });
3416
+ this.#gateway.on("GUILD_DELETE", (data) => {
3417
+ const payload = data;
3418
+ if (payload.unavailable) {
3419
+ this.emit("guildUnavailable" /* GuildUnavailable */, payload);
3420
+ return;
3421
+ }
3422
+ this.guilds.delete(payload.id);
3423
+ this.emit("guildDelete" /* GuildDelete */, payload);
3424
+ });
3425
+ this.#gateway.on("GUILD_MEMBER_ADD", (data) => {
3426
+ const member = data;
3427
+ this.users.set(member.user.id, new User(member.user));
3428
+ this.emit("guildMemberAdd" /* GuildMemberAdd */, member);
3429
+ });
3430
+ this.#gateway.on("GUILD_MEMBER_UPDATE", (data) => {
3431
+ const member = data;
3432
+ this.users.set(member.user.id, new User(member.user));
3433
+ this.emit("guildMemberUpdate" /* GuildMemberUpdate */, member);
3434
+ });
3435
+ this.#gateway.on("GUILD_MEMBER_REMOVE", (data) => this.emit("guildMemberRemove" /* GuildMemberRemove */, data));
3436
+ this.#gateway.on("GUILD_MEMBERS_CHUNK", (data) => this.emit("guildMembersChunk" /* GuildMembersChunk */, data));
3437
+ this.#gateway.on("GUILD_BAN_ADD", (data) => this.emit("guildBanAdd" /* GuildBanAdd */, data));
3438
+ this.#gateway.on("GUILD_BAN_REMOVE", (data) => this.emit("guildBanRemove" /* GuildBanRemove */, data));
3439
+ this.#gateway.on("GUILD_ROLE_CREATE", (data) => this.emit("guildRoleCreate" /* GuildRoleCreate */, data));
3440
+ this.#gateway.on("GUILD_ROLE_UPDATE", (data) => this.emit("guildRoleUpdate" /* GuildRoleUpdate */, data));
3441
+ this.#gateway.on("GUILD_ROLE_DELETE", (data) => this.emit("guildRoleDelete" /* GuildRoleDelete */, data));
3442
+ this.#gateway.on("GUILD_EMOJIS_UPDATE", (data) => this.emit("guildEmojisUpdate" /* GuildEmojisUpdate */, data));
3443
+ this.#gateway.on("GUILD_STICKERS_UPDATE", (data) => this.emit("guildStickersUpdate" /* GuildStickersUpdate */, data));
3444
+ this.#gateway.on("GUILD_INTEGRATIONS_UPDATE", (data) => this.emit("guildIntegrationsUpdate" /* GuildIntegrationsUpdate */, data));
3445
+ this.#gateway.on("GUILD_SCHEDULED_EVENT_CREATE", (data) => this.emit("guildScheduledEventCreate" /* GuildScheduledEventCreate */, data));
3446
+ this.#gateway.on("GUILD_SCHEDULED_EVENT_UPDATE", (data) => this.emit("guildScheduledEventUpdate" /* GuildScheduledEventUpdate */, data));
3447
+ this.#gateway.on("GUILD_SCHEDULED_EVENT_DELETE", (data) => this.emit("guildScheduledEventDelete" /* GuildScheduledEventDelete */, data));
3448
+ this.#gateway.on("GUILD_SCHEDULED_EVENT_USER_ADD", (data) => this.emit("guildScheduledEventUserAdd" /* GuildScheduledEventUserAdd */, data));
3449
+ this.#gateway.on("GUILD_SCHEDULED_EVENT_USER_REMOVE", (data) => this.emit("guildScheduledEventUserRemove" /* GuildScheduledEventUserRemove */, data));
3450
+ this.#gateway.on("AUTO_MODERATION_RULE_CREATE", (data) => this.emit("autoModerationRuleCreate" /* AutoModerationRuleCreate */, data));
3451
+ this.#gateway.on("AUTO_MODERATION_RULE_UPDATE", (data) => this.emit("autoModerationRuleUpdate" /* AutoModerationRuleUpdate */, data));
3452
+ this.#gateway.on("AUTO_MODERATION_RULE_DELETE", (data) => this.emit("autoModerationRuleDelete" /* AutoModerationRuleDelete */, data));
3453
+ this.#gateway.on("AUTO_MODERATION_ACTION_EXECUTION", (data) => this.emit("autoModerationActionExecution" /* AutoModerationActionExecution */, data));
3454
+ this.#gateway.on("CHANNEL_CREATE", (data) => {
3455
+ const channel = new Channel(data, this.#resourceContext);
3456
+ this.channels.update(channel);
3457
+ this.emit("channelCreate" /* ChannelCreate */, channel);
3458
+ });
3459
+ this.#gateway.on("CHANNEL_UPDATE", (data) => {
3460
+ const channel = new Channel(data, this.#resourceContext);
3461
+ this.channels.update(channel);
3462
+ this.emit("channelUpdate" /* ChannelUpdate */, channel);
3463
+ });
3464
+ this.#gateway.on("CHANNEL_DELETE", (data) => {
3465
+ const payload = data;
3466
+ this.channels.delete(payload.id);
3467
+ this.emit("channelDelete" /* ChannelDelete */, payload);
3468
+ });
3469
+ this.#gateway.on("CHANNEL_PINS_UPDATE", (data) => this.emit("channelPinsUpdate" /* ChannelPinsUpdate */, data));
3470
+ this.#gateway.on("THREAD_CREATE", (data) => {
3471
+ const channel = new Channel(data, this.#resourceContext);
3472
+ this.channels.update(channel);
3473
+ this.emit("threadCreate" /* ThreadCreate */, channel);
3474
+ });
3475
+ this.#gateway.on("THREAD_UPDATE", (data) => {
3476
+ const channel = new Channel(data, this.#resourceContext);
3477
+ this.channels.update(channel);
3478
+ this.emit("threadUpdate" /* ThreadUpdate */, channel);
3479
+ });
3480
+ this.#gateway.on("THREAD_DELETE", (data) => {
3481
+ const payload = data;
3482
+ this.channels.delete(payload.id);
3483
+ this.emit("threadDelete" /* ThreadDelete */, payload);
3484
+ });
3485
+ this.#gateway.on("THREAD_LIST_SYNC", (data) => this.emit("threadListSync" /* ThreadListSync */, data));
3486
+ this.#gateway.on("THREAD_MEMBERS_UPDATE", (data) => this.emit("threadMembersUpdate" /* ThreadMembersUpdate */, data));
3487
+ this.#gateway.on("THREAD_MEMBER_UPDATE", (data) => this.emit("threadMemberUpdate" /* ThreadMemberUpdate */, data));
3488
+ this.#gateway.on("STAGE_INSTANCE_CREATE", (data) => this.emit("stageInstanceCreate" /* StageInstanceCreate */, data));
3489
+ this.#gateway.on("STAGE_INSTANCE_UPDATE", (data) => this.emit("stageInstanceUpdate" /* StageInstanceUpdate */, data));
3490
+ this.#gateway.on("STAGE_INSTANCE_DELETE", (data) => this.emit("stageInstanceDelete" /* StageInstanceDelete */, data));
3491
+ this.#gateway.on("INVITE_CREATE", (data) => this.emit("inviteCreate" /* InviteCreate */, data));
3492
+ this.#gateway.on("INVITE_DELETE", (data) => this.emit("inviteDelete" /* InviteDelete */, data));
3493
+ this.#gateway.on("WEBHOOKS_UPDATE", (data) => this.emit("webhooksUpdate" /* WebhooksUpdate */, data));
3494
+ this.#gateway.on("VOICE_STATE_UPDATE", (data) => this.emit("voiceStateUpdate" /* VoiceStateUpdate */, data));
3495
+ this.#gateway.on("VOICE_SERVER_UPDATE", (data) => this.emit("voiceServerUpdate" /* VoiceServerUpdate */, data));
3496
+ this.#gateway.on("PRESENCE_UPDATE", (data) => this.emit("presenceUpdate" /* PresenceUpdate */, data));
3497
+ this.#gateway.on("TYPING_START", (data) => this.emit("typingStart" /* TypingStart */, data));
3498
+ this.#gateway.on("INTERACTION_CREATE", (data) => this.emit("interactionCreate" /* InteractionCreate */, createInteraction(this, data)));
3499
+ this.#gateway.on("RAW", (data) => this.emit("raw" /* Raw */, data));
3500
+ this.#gateway.on("error", (error) => this.emit("error" /* Error */, error));
3501
+ }
3502
+ async login(token) {
3503
+ if (this.state === "destroyed")
3504
+ throw new Error("Cannot login a destroyed client.");
3505
+ if (token?.trim()) {
3506
+ this.rest.setToken(token);
3507
+ this.options.token = token;
3508
+ }
3509
+ const usedToken = this.options.token;
3510
+ if (!usedToken?.trim())
3511
+ throw new TypeError("A bot token is required to log in.");
3512
+ this.state = "connecting";
3513
+ await this.#gateway.connect();
3514
+ return usedToken;
3515
+ }
3516
+ destroy() {
3517
+ this.state = "destroyed";
3518
+ this.#gateway.close();
3519
+ }
3520
+ postInteractionResponse(id, token, response) {
3521
+ return this.rest.post(Routes.interactionCallback(id, token), response.toJSON());
3522
+ }
3523
+ editInteractionReply(token, data) {
3524
+ if (!this.user)
3525
+ return Promise.reject(new Error("Client is unauthenticated."));
3526
+ return this.rest.patch(Routes.interactionOriginalResponse(this.user.id, token), data);
3527
+ }
3528
+ deleteInteractionReply(token) {
3529
+ if (!this.user)
3530
+ return Promise.reject(new Error("Client is unauthenticated."));
3531
+ return this.rest.delete(Routes.interactionOriginalResponse(this.user.id, token));
3532
+ }
3533
+ followUpInteraction(token, data) {
3534
+ if (!this.user)
3535
+ return Promise.reject(new Error("Client is unauthenticated."));
3536
+ return this.rest.post(`/webhooks/${this.user.id}/${token}`, data);
3537
+ }
3538
+ }
3539
+ // packages/formatters/src/index.ts
3540
+ function userMention(id) {
3541
+ return `<@${validateSnowflake(id, "User ID")}>`;
3542
+ }
3543
+ function channelMention(id) {
3544
+ return `<#${validateSnowflake(id, "Channel ID")}>`;
3545
+ }
3546
+ function roleMention(id) {
3547
+ return `<@&${validateSnowflake(id, "Role ID")}>`;
3548
+ }
3549
+ function timestamp(unixSeconds, style) {
3550
+ if (!Number.isFinite(unixSeconds))
3551
+ throw new TypeError("Timestamp must be a finite Unix timestamp.");
3552
+ if (style !== undefined && !/^[tTdDfFR]$/.test(style))
3553
+ throw new RangeError("Invalid Discord timestamp style.");
3554
+ return `<t:${Math.floor(unixSeconds)}${style ? `:${style}` : ""}>`;
3555
+ }
3556
+ function escapeMarkdown(value) {
3557
+ return value.replace(/[\\*_`~|>]/g, "\\$&");
3558
+ }
3559
+ function validateSnowflake(id, field) {
3560
+ const len = id.length;
3561
+ if (len < 1 || len > 20) {
3562
+ throw new TypeError(`${field} must be a valid Discord snowflake.`);
3563
+ }
3564
+ for (let i = 0;i < len; i++) {
3565
+ const code = id.charCodeAt(i);
3566
+ if (code < 48 || code > 57) {
3567
+ throw new TypeError(`${field} must be a valid Discord snowflake.`);
3568
+ }
3569
+ }
3570
+ return id;
3571
+ }
3572
+ // packages/handlers/src/index.ts
3573
+ class HandlerRegistry {
3574
+ #handlers = new Map;
3575
+ on(event, handler) {
3576
+ let handlers = this.#handlers.get(event);
3577
+ if (!handlers) {
3578
+ handlers = new Set;
3579
+ this.#handlers.set(event, handlers);
3580
+ }
3581
+ handlers.add(handler);
3582
+ return this;
3583
+ }
3584
+ once(event, handler) {
3585
+ const wrapped = (...args) => {
3586
+ this.off(event, wrapped);
3587
+ return handler(...args);
3588
+ };
3589
+ return this.on(event, wrapped);
3590
+ }
3591
+ off(event, handler) {
3592
+ this.#handlers.get(event)?.delete(handler);
3593
+ return this;
3594
+ }
3595
+ async dispatch(event, ...args) {
3596
+ for (const handler of this.#handlers.get(event) ?? [])
3597
+ await handler(...args);
3598
+ }
3599
+ emit(event, ...args) {
3600
+ return this.dispatch(event, ...args);
3601
+ }
3602
+ }
3603
+ // packages/sharding/src/bus.ts
3604
+ class ShardBus {
3605
+ #channel;
3606
+ #handlers = new Map;
3607
+ #shardId;
3608
+ #namespace;
3609
+ channelName;
3610
+ #counter = 0;
3611
+ constructor(shardId, channelName) {
3612
+ if (!Number.isInteger(shardId) || shardId < 0)
3613
+ throw new RangeError("Shard ID must be a non-negative integer.");
3614
+ if (!channelName?.trim())
3615
+ throw new TypeError("An application-specific shard channel name is required.");
3616
+ this.#shardId = shardId;
3617
+ this.#namespace = channelName.trim();
3618
+ this.channelName = this.#namespace;
3619
+ this.#channel = new BroadcastChannel(this.channelName);
3620
+ this.#channel.addEventListener("message", (event) => this.#dispatch(event.data));
3621
+ }
3622
+ on(type, handler) {
3623
+ if (!type.trim() || typeof handler !== "function")
3624
+ throw new TypeError("Shard message type and handler are required.");
3625
+ let handlers = this.#handlers.get(type);
3626
+ if (!handlers)
3627
+ this.#handlers.set(type, handlers = new Set);
3628
+ handlers.add(handler);
3629
+ return this;
3630
+ }
3631
+ off(type, handler) {
3632
+ this.#handlers.get(type)?.delete(handler);
3633
+ return this;
3634
+ }
3635
+ send(target, type, data) {
3636
+ if (!Number.isInteger(target) || target < 0)
3637
+ throw new RangeError("Shard target must be a non-negative integer.");
3638
+ return this.#publish(target, type, data);
3639
+ }
3640
+ broadcast(type, data) {
3641
+ return this.#publish(null, type, data);
3642
+ }
3643
+ close() {
3644
+ this.#channel.close();
3645
+ this.#handlers.clear();
3646
+ }
3647
+ #publish(target, type, data) {
3648
+ if (!type.trim())
3649
+ throw new TypeError("Shard message type is required.");
3650
+ const id = `${this.#namespace}:${this.#shardId}:${++this.#counter}`;
3651
+ this.#channel.postMessage({
3652
+ source: this.#shardId,
3653
+ target,
3654
+ type,
3655
+ data,
3656
+ id
3657
+ });
3658
+ return id;
3659
+ }
3660
+ #dispatch(message) {
3661
+ if (!message || typeof message !== "object" || typeof message.type !== "string")
3662
+ return;
3663
+ if (message.source === this.#shardId || message.target !== null && message.target !== this.#shardId)
3664
+ return;
3665
+ for (const handler of this.#handlers.get(message.type) ?? []) {
3666
+ try {
3667
+ const result = handler(message);
3668
+ if (result && typeof result.then === "function")
3669
+ Promise.resolve(result).catch(() => {
3670
+ return;
3671
+ });
3672
+ } catch {}
3673
+ }
3674
+ }
3675
+ }
3676
+
3677
+ // packages/sharding/src/index.ts
3678
+ class ShardManager {
3679
+ shards = new Map;
3680
+ get shardCount() {
3681
+ return this.shards.size;
3682
+ }
3683
+ #options;
3684
+ #resolved = false;
3685
+ #destroyed = false;
3686
+ constructor(options) {
3687
+ if (!options.token?.trim())
3688
+ throw new TypeError("A Discord bot token is required.");
3689
+ if (!Number.isInteger(options.intents) || options.intents < 0)
3690
+ throw new TypeError("Gateway intents must be a non-negative integer.");
3691
+ const count = options.shardCount === "auto" || options.shardCount === undefined ? 1 : options.shardCount;
3692
+ if (!Number.isInteger(count) || count < 1)
3693
+ throw new RangeError("Shard count must be a positive integer.");
3694
+ this.#options = { ...options };
3695
+ if (options.shardCount !== "auto")
3696
+ this.#initialize(count);
3697
+ }
3698
+ async fetchRecommendedShardCount() {
3699
+ const response = await fetch("https://discord.com/api/v10/gateway/bot", {
3700
+ headers: {
3701
+ Authorization: `Bot ${this.#options.token}`,
3702
+ "User-Agent": "Lunibee/0.1.0"
3703
+ }
3704
+ });
3705
+ if (!response.ok)
3706
+ throw new Error(`Gateway discovery failed with status ${response.status}`);
3707
+ const data = await response.json();
3708
+ if (typeof data.shards !== "number" || !Number.isInteger(data.shards) || data.shards < 1)
3709
+ throw new Error("Gateway discovery returned an invalid shard count.");
3710
+ return data.shards;
3711
+ }
3712
+ async connect() {
3713
+ await this.#ensureInitialized();
3714
+ for (const [id, shard] of this.shards) {
3715
+ try {
3716
+ await shard.connect();
3717
+ } catch (error) {
3718
+ this.destroy();
3719
+ throw new Error(`Failed to connect shard ${id}.`, { cause: error });
3720
+ }
3721
+ if (id + 1 < this.shardCount && this.#options.spawnDelay && this.#options.spawnDelay > 0)
3722
+ await Bun.sleep(this.#options.spawnDelay);
3723
+ }
3724
+ }
3725
+ destroy() {
3726
+ for (const shard of this.shards.values())
3727
+ shard.close();
3728
+ this.shards.clear();
3729
+ this.#resolved = false;
3730
+ this.#destroyed = true;
3731
+ }
3732
+ getShardIdForGuild(guildId) {
3733
+ const id = BigInt(guildId);
3734
+ return Number((id >> 22n) % BigInt(this.shardCount || 1));
3735
+ }
3736
+ get(id) {
3737
+ return this.shards.get(id);
3738
+ }
3739
+ values() {
3740
+ return [...this.shards].map(([id, gateway]) => ({ id, gateway }));
3741
+ }
3742
+ async#ensureInitialized() {
3743
+ if (this.#resolved)
3744
+ return;
3745
+ if (this.#destroyed)
3746
+ this.#destroyed = false;
3747
+ const count = this.#options.shardCount === "auto" ? await this.fetchRecommendedShardCount() : this.#options.shardCount ?? 1;
3748
+ this.#initialize(count);
3749
+ }
3750
+ #initialize(count) {
3751
+ if (this.#resolved)
3752
+ return;
3753
+ for (let id = 0;id < count; id++)
3754
+ this.shards.set(id, this.#createShard(id, count));
3755
+ this.#resolved = true;
3756
+ }
3757
+ #createShard(id, count) {
3758
+ return new Gateway({
3759
+ token: this.#options.token,
3760
+ intents: this.#options.intents,
3761
+ shardId: id,
3762
+ shardCount: count,
3763
+ reconnect: this.#options.reconnect ?? true
3764
+ });
3765
+ }
3766
+ }
3767
+ // packages/utils/src/index.ts
3768
+ function sleep(ms) {
3769
+ return new Promise((resolve) => setTimeout(resolve, ms));
3770
+ }
3771
+ function randomInt(min, max) {
3772
+ return Math.floor(Math.random() * (max - min + 1)) + min;
3773
+ }
3774
+ function isSnowflake(value) {
3775
+ return /^\d{16,22}$/.test(value);
3776
+ }
3777
+ // packages/voice/src/index.ts
3778
+ var VoiceConnectionState;
3779
+ ((VoiceConnectionState2) => {
3780
+ VoiceConnectionState2["Disconnected"] = "disconnected";
3781
+ VoiceConnectionState2["Connecting"] = "connecting";
3782
+ VoiceConnectionState2["Connected"] = "connected";
3783
+ VoiceConnectionState2["Destroyed"] = "destroyed";
3784
+ })(VoiceConnectionState ||= {});
3785
+
3786
+ class VoiceError extends Error {
3787
+ constructor(message, options) {
3788
+ super(message, options);
3789
+ this.name = "VoiceError";
3790
+ }
3791
+ }
3792
+ var SpeakingFlags = {
3793
+ Microphone: 1,
3794
+ Soundshare: 2,
3795
+ Priority: 4
3796
+ };
3797
+
3798
+ class VoiceConnection {
3799
+ state = "disconnected" /* Disconnected */;
3800
+ guildId;
3801
+ channelId;
3802
+ selfMute;
3803
+ selfDeaf;
3804
+ gateway;
3805
+ udp;
3806
+ #listeners = new Map;
3807
+ constructor(options) {
3808
+ const resolved = typeof options === "string" ? { guildId: options } : options;
3809
+ if (!resolved.guildId?.trim()) {
3810
+ throw new TypeError("A guild ID is required for a voice connection.");
3811
+ }
3812
+ this.guildId = resolved.guildId;
3813
+ this.channelId = resolved.channelId;
3814
+ this.selfMute = resolved.selfMute ?? false;
3815
+ this.selfDeaf = resolved.selfDeaf ?? false;
3816
+ }
3817
+ on(event, listener) {
3818
+ if (typeof listener !== "function")
3819
+ throw new TypeError("Voice listener must be a function.");
3820
+ let listeners = this.#listeners.get(event);
3821
+ if (!listeners)
3822
+ this.#listeners.set(event, listeners = new Set);
3823
+ listeners.add(listener);
3824
+ return this;
3825
+ }
3826
+ off(event, listener) {
3827
+ this.#listeners.get(event)?.delete(listener);
3828
+ return this;
3829
+ }
3830
+ attachTransports(gateway, udp) {
3831
+ this.assertUsable();
3832
+ if (!gateway || !udp)
3833
+ throw new TypeError("Both voice gateway and UDP transports are required.");
3834
+ if (this.gateway || this.udp)
3835
+ this.#closeTransports();
3836
+ this.gateway = gateway;
3837
+ this.udp = udp;
3838
+ return this;
3839
+ }
3840
+ connect() {
3841
+ this.assertUsable();
3842
+ if (this.state === "connected" /* Connected */)
3843
+ return;
3844
+ this.#transition("connecting" /* Connecting */);
3845
+ if (this.state !== "connecting" /* Connecting */)
3846
+ return;
3847
+ this.#transition("connected" /* Connected */);
3848
+ }
3849
+ disconnect() {
3850
+ if (this.state === "destroyed" /* Destroyed */)
3851
+ return;
3852
+ this.#closeTransports();
3853
+ this.#transition("disconnected" /* Disconnected */);
3854
+ }
3855
+ destroy() {
3856
+ if (this.state === "destroyed" /* Destroyed */)
3857
+ return;
3858
+ this.#closeTransports();
3859
+ this.channelId = undefined;
3860
+ this.#transition("destroyed" /* Destroyed */);
3861
+ this.#listeners.clear();
3862
+ }
3863
+ setChannel(channelId) {
3864
+ this.assertUsable();
3865
+ if (!channelId?.trim())
3866
+ throw new TypeError("A voice channel ID is required.");
3867
+ this.channelId = channelId;
3868
+ }
3869
+ setSuppression(options) {
3870
+ this.assertUsable();
3871
+ if (options.selfMute !== undefined)
3872
+ this.selfMute = options.selfMute;
3873
+ if (options.selfDeaf !== undefined)
3874
+ this.selfDeaf = options.selfDeaf;
3875
+ }
3876
+ setSpeaking(flags = SpeakingFlags.Microphone) {
3877
+ this.assertUsable();
3878
+ if (!this.gateway) {
3879
+ throw new VoiceError("A voice gateway transport is required to change speaking state.");
3880
+ }
3881
+ this.gateway.send({ op: 5, d: { speaking: flags, delay: 0, ssrc: 0 } });
3882
+ this.#emit("speaking", flags, 0);
3883
+ }
3884
+ #assertUsable() {
3885
+ if (this.state === "destroyed" /* Destroyed */) {
3886
+ throw new VoiceError("Voice connection has been destroyed.");
3887
+ }
3888
+ }
3889
+ #closeTransports() {
3890
+ try {
3891
+ this.gateway?.close(1000, "Voice connection replaced or closed");
3892
+ } catch (error) {
3893
+ this.#emit("error", error instanceof VoiceError ? error : new VoiceError("Voice gateway cleanup failed.", { cause: error }));
3894
+ }
3895
+ try {
3896
+ this.udp?.close();
3897
+ } catch (error) {
3898
+ this.#emit("error", error instanceof VoiceError ? error : new VoiceError("Voice UDP cleanup failed.", { cause: error }));
3899
+ }
3900
+ this.gateway = undefined;
3901
+ this.udp = undefined;
3902
+ }
3903
+ #transition(next) {
3904
+ const previous = this.state;
3905
+ this.state = next;
3906
+ if (previous === next)
3907
+ return;
3908
+ for (const listener of this.#listeners.get("stateChange") ?? []) {
3909
+ try {
3910
+ listener(next, previous);
3911
+ } catch (error) {
3912
+ this.#emit("error", error instanceof VoiceError ? error : new VoiceError("Voice event listener failed.", { cause: error }));
3913
+ }
3914
+ if (this.state !== next && next !== "destroyed" /* Destroyed */)
3915
+ return;
3916
+ }
3917
+ }
3918
+ #emit(event, ...args) {
3919
+ for (const listener of this.#listeners.get(event) ?? []) {
3920
+ try {
3921
+ listener(...args);
3922
+ } catch {}
3923
+ }
3924
+ }
3925
+ assertUsable() {
3926
+ this.#assertUsable();
3927
+ }
3928
+ }
3929
+ // packages/builders/src/embed.ts
3930
+ class EmbedBuilder {
3931
+ #data = {};
3932
+ setTitle(value) {
3933
+ this.#data.title = validate(value, 256, "Embed title");
3934
+ return this;
3935
+ }
3936
+ setDescription(value) {
3937
+ this.#data.description = validate(value, 4096, "Embed description");
3938
+ return this;
3939
+ }
3940
+ setURL(value) {
3941
+ this.#data.url = url(value, "Embed URL");
3942
+ return this;
3943
+ }
3944
+ setColor(value) {
3945
+ if (!Number.isInteger(value) || value < 0 || value > 16777215)
3946
+ throw new RangeError("Embed color must be an integer between 0 and 16777215.");
3947
+ this.#data.color = value;
3948
+ return this;
3949
+ }
3950
+ setTimestamp(value = new Date) {
3951
+ const date = value instanceof Date ? value : new Date(value);
3952
+ if (Number.isNaN(date.getTime()))
3953
+ throw new RangeError("Embed timestamp must be a valid date.");
3954
+ this.#data.timestamp = date.toISOString();
3955
+ return this;
3956
+ }
3957
+ setFooter(value) {
3958
+ this.#data.footer = {
3959
+ text: validate(value.text, 2048, "Footer text"),
3960
+ ...value.icon_url ? { icon_url: url(value.icon_url, "Footer icon URL") } : {}
3961
+ };
3962
+ return this;
3963
+ }
3964
+ setAuthor(value) {
3965
+ this.#data.author = {
3966
+ name: validate(value.name, 256, "Author name"),
3967
+ ...value.url ? { url: url(value.url, "Author URL") } : {},
3968
+ ...value.icon_url ? { icon_url: url(value.icon_url, "Author icon URL") } : {}
3969
+ };
3970
+ return this;
3971
+ }
3972
+ setThumbnail(value) {
3973
+ const valueURL = typeof value === "string" ? value : value.url;
3974
+ this.#data.thumbnail = { url: url(valueURL, "Thumbnail URL") };
3975
+ return this;
3976
+ }
3977
+ setImage(value) {
3978
+ const valueURL = typeof value === "string" ? value : value.url;
3979
+ this.#data.image = { url: url(valueURL, "Image URL") };
3980
+ return this;
3981
+ }
3982
+ addFields(...fields) {
3983
+ if (!fields.length)
3984
+ throw new TypeError("At least one embed field is required.");
3985
+ const current = this.#data.fields ?? [];
3986
+ if (current.length + fields.length > 25)
3987
+ throw new RangeError("An embed cannot contain more than 25 fields.");
3988
+ for (const field of fields) {
3989
+ validate(field.name, 256, "Embed field name");
3990
+ validate(field.value, 1024, "Embed field value");
3991
+ }
3992
+ this.#data.fields = [...current, ...fields.map((field) => ({ ...field }))];
3993
+ return this;
3994
+ }
3995
+ setFields(fields) {
3996
+ this.#data.fields = [];
3997
+ return this.addFields(...fields);
3998
+ }
3999
+ spliceFields(index, deleteCount, ...fields) {
4000
+ const current = [...this.#data.fields ?? []];
4001
+ if (!Number.isInteger(index) || !Number.isInteger(deleteCount) || index < 0 || deleteCount < 0)
4002
+ throw new RangeError("Field index and delete count must be non-negative integers.");
4003
+ current.splice(index, deleteCount, ...fields);
4004
+ if (current.length > 25)
4005
+ throw new RangeError("An embed cannot contain more than 25 fields.");
4006
+ this.#data.fields = current;
4007
+ return this;
4008
+ }
4009
+ clearFields() {
4010
+ delete this.#data.fields;
4011
+ return this;
4012
+ }
4013
+ clearTitle() {
4014
+ delete this.#data.title;
4015
+ return this;
4016
+ }
4017
+ clearDescription() {
4018
+ delete this.#data.description;
4019
+ return this;
4020
+ }
4021
+ get data() {
4022
+ return this.toJSON();
4023
+ }
4024
+ toJSON() {
4025
+ return structuredClone(this.#data);
4026
+ }
4027
+ }
4028
+ function validate(value, max, field) {
4029
+ if (typeof value !== "string" || value.length === 0 || value.length > max)
4030
+ throw new RangeError(`${field} must contain 1-${max} characters.`);
4031
+ return value;
4032
+ }
4033
+ function url(value, field) {
4034
+ try {
4035
+ return new URL(value).toString();
4036
+ } catch (error) {
4037
+ throw new TypeError(`${field} must be a valid URL.`, { cause: error });
4038
+ }
4039
+ }
4040
+ // packages/builders/src/components.ts
4041
+ var ComponentType = {
4042
+ ActionRow: 1,
4043
+ Button: 2,
4044
+ StringSelect: 3,
4045
+ TextInput: 4,
4046
+ UserSelect: 5,
4047
+ RoleSelect: 6,
4048
+ MentionableSelect: 7,
4049
+ ChannelSelect: 8,
4050
+ Section: 9,
4051
+ TextDisplay: 10,
4052
+ Thumbnail: 11,
4053
+ MediaGallery: 12,
4054
+ File: 13,
4055
+ Separator: 14,
4056
+ ContentInventoryEntry: 16,
4057
+ Container: 17
4058
+ };
4059
+ var ButtonStyle = {
4060
+ Primary: 1,
4061
+ Secondary: 2,
4062
+ Success: 3,
4063
+ Danger: 4,
4064
+ Link: 5
4065
+ };
4066
+ var TextInputStyle = { Short: 1, Paragraph: 2 };
4067
+
4068
+ class ActionRowBuilder {
4069
+ #components = [];
4070
+ addComponents(...components) {
4071
+ if (!components.length)
4072
+ throw new TypeError("At least one component is required.");
4073
+ if (this.#components.length + components.length > 5)
2673
4074
  throw new RangeError("An action row cannot contain more than 5 components.");
2674
4075
  this.#components.push(...components);
2675
4076
  return this;
@@ -2909,1174 +4310,587 @@ class TextInputBuilder {
2909
4310
  this.#data.value = value;
2910
4311
  return this;
2911
4312
  }
2912
- toJSON() {
2913
- return structuredClone(this.#data);
2914
- }
2915
- }
2916
- function validateText(value, max, field) {
2917
- if (typeof value !== "string")
2918
- throw new TypeError(`${field} must be a string.`);
2919
- if (!value.trim())
2920
- throw new RangeError(`${field} must be a non-empty string.`);
2921
- if (value.length > max)
2922
- throw new RangeError(`${field} cannot exceed ${max} characters.`);
2923
- }
2924
- function validateCount(value, field, min, max = 25) {
2925
- if (!Number.isInteger(value) || value < min || value > max)
2926
- throw new RangeError(`${field} must be an integer between ${min} and ${max}.`);
2927
- }
2928
- function validateLength(value, field, max = 4000) {
2929
- if (!Number.isInteger(value) || value < 0 || value > max)
2930
- throw new RangeError(`${field} must be an integer between 0 and ${max}.`);
2931
- }
2932
- // packages/builders/src/commands.ts
2933
- var ApplicationCommandOptionType = {
2934
- Subcommand: 1,
2935
- SubcommandGroup: 2,
2936
- String: 3,
2937
- Integer: 4,
2938
- Boolean: 5,
2939
- User: 6,
2940
- Channel: 7,
2941
- Role: 8,
2942
- Mentionable: 9,
2943
- Number: 10,
2944
- Attachment: 11
2945
- };
2946
-
2947
- class SlashCommandBuilder {
2948
- #data = { type: 1 };
2949
- setName(name) {
2950
- validateName(name, "Command name");
2951
- this.#data.name = name;
2952
- return this;
2953
- }
2954
- setDescription(description) {
2955
- validateText2(description, "Command description", 100);
2956
- this.#data.description = description;
2957
- return this;
2958
- }
2959
- setDMPermission(enabled) {
2960
- this.#data.dm_permission = enabled;
2961
- return this;
2962
- }
2963
- setNSFW(nsfw = true) {
2964
- this.#data.nsfw = nsfw;
2965
- return this;
2966
- }
2967
- setNsfw(nsfw = true) {
2968
- return this.setNSFW(nsfw);
2969
- }
2970
- setDefaultMemberPermissions(permissions) {
2971
- this.#data.default_member_permissions = permissions === null ? null : BigInt(permissions).toString();
2972
- return this;
2973
- }
2974
- setIntegrationTypes(...types) {
2975
- this.#data.integration_types = [...types];
2976
- return this;
2977
- }
2978
- addStringOption(configure) {
2979
- return this.addOption(configure(new StringOptionBuilder));
2980
- }
2981
- addIntegerOption(configure) {
2982
- return this.addOption(configure(new IntegerOptionBuilder));
2983
- }
2984
- addNumberOption(configure) {
2985
- return this.addOption(configure(new NumberOptionBuilder));
2986
- }
2987
- addBooleanOption(configure) {
2988
- return this.addOption(configure(new BooleanOptionBuilder));
2989
- }
2990
- addUserOption(configure) {
2991
- return this.addOption(configure(new UserOptionBuilder));
2992
- }
2993
- addChannelOption(configure) {
2994
- return this.addOption(configure(new ChannelOptionBuilder));
2995
- }
2996
- addRoleOption(configure) {
2997
- return this.addOption(configure(new RoleOptionBuilder));
2998
- }
2999
- addMentionableOption(configure) {
3000
- return this.addOption(configure(new MentionableOptionBuilder));
3001
- }
3002
- addAttachmentOption(configure) {
3003
- return this.addOption(configure(new AttachmentOptionBuilder));
3004
- }
3005
- addSubcommand(configure) {
3006
- return this.addOption(configure(new SubcommandBuilder));
3007
- }
3008
- addSubcommandGroup(configure) {
3009
- return this.addOption(configure(new SubcommandGroupBuilder));
3010
- }
3011
- toJSON() {
3012
- return structuredClone(this.#data);
3013
- }
3014
- addOption(option) {
3015
- const options = this.#data.options ?? [];
3016
- if (options.length >= 25)
3017
- throw new RangeError("An application command cannot contain more than 25 options.");
3018
- const payload = option.toJSON();
3019
- if (options.some((existing) => existing.name === payload.name))
3020
- throw new RangeError(`Duplicate option name: ${String(payload.name)}.`);
3021
- if (payload.required === true && options.some((existing) => existing.required !== true))
3022
- throw new RangeError("Required application command options must be placed before optional options.");
3023
- options.push(payload);
3024
- this.#data.options = options;
3025
- return this;
3026
- }
3027
- }
3028
-
3029
- class CommandOptionBuilder {
3030
- data;
3031
- constructor(type) {
3032
- this.data = { type };
3033
- }
3034
- setName(name) {
3035
- validateName(name, "Option name");
3036
- this.data.name = name;
3037
- return this;
3038
- }
3039
- setDescription(description) {
3040
- validateText2(description, "Option description", 100);
3041
- this.data.description = description;
3042
- return this;
3043
- }
3044
- setRequired(required = true) {
3045
- this.data.required = required;
3046
- return this;
3047
- }
3048
- setAutocomplete(enabled = true) {
3049
- this.data.autocomplete = enabled;
3050
- return this;
3051
- }
3052
- toJSON() {
3053
- return structuredClone(this.data);
3054
- }
3055
- }
3056
-
3057
- class StringOptionBuilder extends CommandOptionBuilder {
3058
- constructor() {
3059
- super(ApplicationCommandOptionType.String);
3060
- }
3061
- addChoices(...choices) {
3062
- const current = this.data.choices ?? [];
3063
- if (!choices.length)
3064
- throw new TypeError("At least one choice is required.");
3065
- if (this.data.autocomplete === true)
3066
- throw new RangeError("Autocomplete options cannot define choices.");
3067
- if (current.length + choices.length > 25)
3068
- throw new RangeError("An option cannot contain more than 25 choices.");
3069
- for (const choice of choices) {
3070
- validateText2(choice.name, "Choice name", 100);
3071
- validateText2(choice.value, "Choice value", 100);
3072
- }
3073
- this.data.choices = [
3074
- ...current,
3075
- ...choices.map((choice) => ({ ...choice }))
3076
- ];
3077
- return this;
3078
- }
3079
- setMinLength(value) {
3080
- validateIntegerRange(value, 0, 6000, "min_length");
3081
- this.data.min_length = value;
3082
- return this;
3083
- }
3084
- setMaxLength(value) {
3085
- validateIntegerRange(value, 1, 6000, "max_length");
3086
- if (this.data.min_length !== undefined && this.data.min_length > value)
3087
- throw new RangeError("min_length cannot exceed max_length.");
3088
- this.data.max_length = value;
3089
- return this;
3090
- }
3091
- }
3092
-
3093
- class IntegerOptionBuilder extends CommandOptionBuilder {
3094
- constructor() {
3095
- super(ApplicationCommandOptionType.Integer);
3096
- }
3097
- setMinValue(value) {
3098
- validateNumberRange(value, -9007199254740991, 9007199254740991, "min_value", true);
3099
- this.data.min_value = value;
3100
- return this;
3101
- }
3102
- setMaxValue(value) {
3103
- validateNumberRange(value, -9007199254740991, 9007199254740991, "max_value", true);
3104
- if (this.data.min_value !== undefined && this.data.min_value > value)
3105
- throw new RangeError("min_value cannot exceed max_value.");
3106
- this.data.max_value = value;
3107
- return this;
3108
- }
3109
- setAutocomplete(enabled = true) {
3110
- if (enabled && Array.isArray(this.data.choices) && this.data.choices.length)
3111
- throw new RangeError("Autocomplete options cannot define choices.");
3112
- this.data.autocomplete = enabled;
3113
- return this;
3114
- }
3115
- addChoices(...choices) {
3116
- const current = this.data.choices ?? [];
3117
- if (!choices.length)
3118
- throw new TypeError("At least one choice is required.");
3119
- if (this.data.autocomplete === true)
3120
- throw new RangeError("Autocomplete options cannot define choices.");
3121
- if (current.length + choices.length > 25)
3122
- throw new RangeError("An option cannot contain more than 25 choices.");
3123
- this.data.choices = [...current, ...choices];
3124
- return this;
3125
- }
3126
- }
3127
-
3128
- class NumberOptionBuilder extends CommandOptionBuilder {
3129
- constructor() {
3130
- super(ApplicationCommandOptionType.Number);
3131
- }
3132
- setMinValue(value) {
3133
- validateNumberRange(value, -9007199254740991, 9007199254740991, "min_value", false);
3134
- this.data.min_value = value;
3135
- return this;
3136
- }
3137
- setMaxValue(value) {
3138
- validateNumberRange(value, -9007199254740991, 9007199254740991, "max_value", false);
3139
- if (this.data.min_value !== undefined && this.data.min_value > value)
3140
- throw new RangeError("min_value cannot exceed max_value.");
3141
- this.data.max_value = value;
3142
- return this;
3143
- }
3144
- setAutocomplete(enabled = true) {
3145
- if (enabled && Array.isArray(this.data.choices) && this.data.choices.length)
3146
- throw new RangeError("Autocomplete options cannot define choices.");
3147
- this.data.autocomplete = enabled;
3148
- return this;
3149
- }
3150
- addChoices(...choices) {
3151
- const current = this.data.choices ?? [];
3152
- if (!choices.length)
3153
- throw new TypeError("At least one choice is required.");
3154
- if (this.data.autocomplete === true)
3155
- throw new RangeError("Autocomplete options cannot define choices.");
3156
- if (current.length + choices.length > 25)
3157
- throw new RangeError("An option cannot contain more than 25 choices.");
3158
- this.data.choices = [...current, ...choices];
3159
- return this;
3160
- }
3161
- }
3162
-
3163
- class BooleanOptionBuilder extends CommandOptionBuilder {
3164
- constructor() {
3165
- super(ApplicationCommandOptionType.Boolean);
3166
- }
3167
- }
3168
-
3169
- class UserOptionBuilder extends CommandOptionBuilder {
3170
- constructor() {
3171
- super(ApplicationCommandOptionType.User);
4313
+ toJSON() {
4314
+ return structuredClone(this.#data);
3172
4315
  }
3173
4316
  }
3174
4317
 
3175
- class RoleOptionBuilder extends CommandOptionBuilder {
3176
- constructor() {
3177
- super(ApplicationCommandOptionType.Role);
4318
+ class ContainerBuilder {
4319
+ #components = [];
4320
+ #accentColor;
4321
+ addComponents(...components) {
4322
+ if (!components.length)
4323
+ throw new TypeError("At least one component is required.");
4324
+ this.#components.push(...components);
4325
+ return this;
3178
4326
  }
3179
- }
3180
-
3181
- class MentionableOptionBuilder extends CommandOptionBuilder {
3182
- constructor() {
3183
- super(ApplicationCommandOptionType.Mentionable);
4327
+ setAccentColor(color) {
4328
+ if (!Number.isInteger(color) || color < 0 || color > 16777215) {
4329
+ throw new RangeError("Accent color must be an integer between 0 and 16777215 (0xFFFFFF).");
4330
+ }
4331
+ this.#accentColor = color;
4332
+ return this;
3184
4333
  }
3185
- }
3186
-
3187
- class AttachmentOptionBuilder extends CommandOptionBuilder {
3188
- constructor() {
3189
- super(ApplicationCommandOptionType.Attachment);
4334
+ toJSON() {
4335
+ return {
4336
+ type: ComponentType.Container,
4337
+ components: this.#components.map((c) => c.toJSON()),
4338
+ accent_color: this.#accentColor
4339
+ };
3190
4340
  }
3191
4341
  }
3192
4342
 
3193
- class ChannelOptionBuilder extends CommandOptionBuilder {
3194
- constructor() {
3195
- super(ApplicationCommandOptionType.Channel);
4343
+ class SectionBuilder {
4344
+ #components = [];
4345
+ #accessory;
4346
+ addComponents(...components) {
4347
+ if (!components.length)
4348
+ throw new TypeError("At least one component is required.");
4349
+ this.#components.push(...components);
4350
+ return this;
3196
4351
  }
3197
- addChannelTypes(...types) {
3198
- if (types.some((type) => !Number.isInteger(type) || type < 0))
3199
- throw new RangeError("Channel types must be non-negative integers.");
3200
- this.data.channel_types = [...new Set(types)];
4352
+ setAccessory(accessory) {
4353
+ this.#accessory = accessory;
3201
4354
  return this;
3202
4355
  }
4356
+ toJSON() {
4357
+ return {
4358
+ type: ComponentType.Section,
4359
+ components: this.#components.length ? this.#components.map((c) => c.toJSON()) : undefined,
4360
+ accessory: this.#accessory?.toJSON()
4361
+ };
4362
+ }
3203
4363
  }
3204
4364
 
3205
- class SubcommandBuilder extends CommandOptionBuilder {
3206
- constructor() {
3207
- super(ApplicationCommandOptionType.Subcommand);
4365
+ class TextDisplayBuilder {
4366
+ #content = "";
4367
+ setContent(content) {
4368
+ validateText(content, 4000, "Text display content");
4369
+ this.#content = content;
4370
+ return this;
3208
4371
  }
3209
- addStringOption(configure) {
3210
- return this.addChildOption(configure(new StringOptionBuilder));
4372
+ toJSON() {
4373
+ return {
4374
+ type: ComponentType.TextDisplay,
4375
+ content: this.#content
4376
+ };
3211
4377
  }
3212
- addIntegerOption(configure) {
3213
- return this.addChildOption(configure(new IntegerOptionBuilder));
4378
+ }
4379
+
4380
+ class MediaGalleryBuilder {
4381
+ #items = [];
4382
+ addItems(...items) {
4383
+ if (!items.length) {
4384
+ throw new TypeError("At least one media gallery item is required.");
4385
+ }
4386
+ if (this.#items.length + items.length > 10) {
4387
+ throw new RangeError("MediaGallery can only contain up to 10 items.");
4388
+ }
4389
+ this.#items.push(...items.map((item) => ({ media: item })));
4390
+ return this;
3214
4391
  }
3215
- addNumberOption(configure) {
3216
- return this.addChildOption(configure(new NumberOptionBuilder));
4392
+ toJSON() {
4393
+ return {
4394
+ type: ComponentType.MediaGallery,
4395
+ items: structuredClone(this.#items)
4396
+ };
3217
4397
  }
3218
- addBooleanOption(configure) {
3219
- return this.addChildOption(configure(new BooleanOptionBuilder));
4398
+ }
4399
+
4400
+ class FileComponentBuilder {
4401
+ #url = "";
4402
+ #spoiler;
4403
+ setUrl(url2) {
4404
+ validateText(url2, 2048, "File component URL");
4405
+ this.#url = url2;
4406
+ return this;
3220
4407
  }
3221
- addUserOption(configure) {
3222
- return this.addChildOption(configure(new UserOptionBuilder));
4408
+ setSpoiler(spoiler = true) {
4409
+ this.#spoiler = spoiler;
4410
+ return this;
3223
4411
  }
3224
- addChannelOption(configure) {
3225
- return this.addChildOption(configure(new ChannelOptionBuilder));
4412
+ toJSON() {
4413
+ if (!this.#url)
4414
+ throw new Error("File component must have a URL.");
4415
+ const data = {
4416
+ type: ComponentType.File,
4417
+ file: { url: this.#url }
4418
+ };
4419
+ if (this.#spoiler !== undefined)
4420
+ data.spoiler = this.#spoiler;
4421
+ return data;
3226
4422
  }
3227
- addRoleOption(configure) {
3228
- return this.addChildOption(configure(new RoleOptionBuilder));
4423
+ }
4424
+
4425
+ class SeparatorBuilder {
4426
+ #spacing;
4427
+ #divider;
4428
+ setSpacing(spacing) {
4429
+ this.#spacing = spacing;
4430
+ return this;
3229
4431
  }
3230
- addMentionableOption(configure) {
3231
- return this.addChildOption(configure(new MentionableOptionBuilder));
4432
+ setDivider(divider = true) {
4433
+ this.#divider = divider;
4434
+ return this;
3232
4435
  }
3233
- addAttachmentOption(configure) {
3234
- return this.addChildOption(configure(new AttachmentOptionBuilder));
4436
+ toJSON() {
4437
+ const data = {
4438
+ type: ComponentType.Separator
4439
+ };
4440
+ if (this.#spacing !== undefined)
4441
+ data.spacing = this.#spacing;
4442
+ if (this.#divider !== undefined)
4443
+ data.divider = this.#divider;
4444
+ return data;
3235
4445
  }
3236
- addChildOption(option) {
3237
- const options = this.data.options ?? [];
3238
- if (options.length >= 25)
3239
- throw new RangeError("A subcommand cannot contain more than 25 options.");
3240
- const payload = option.toJSON();
3241
- if (options.some((existing) => existing.name === payload.name))
3242
- throw new RangeError(`Duplicate option name: ${String(payload.name)}.`);
3243
- if (payload.required === true && options.some((existing) => existing.required !== true))
3244
- throw new RangeError("Required subcommand options must be placed before optional options.");
3245
- if (options.some((existing) => existing.type === ApplicationCommandOptionType.Subcommand))
3246
- throw new RangeError("Subcommands cannot contain nested subcommands.");
3247
- options.push(payload);
3248
- this.data.options = options;
4446
+ }
4447
+
4448
+ class ThumbnailBuilder {
4449
+ #url = "";
4450
+ setUrl(url2) {
4451
+ validateText(url2, 2048, "Thumbnail URL");
4452
+ this.#url = url2;
3249
4453
  return this;
3250
4454
  }
4455
+ toJSON() {
4456
+ return {
4457
+ type: ComponentType.Thumbnail,
4458
+ url: this.#url
4459
+ };
4460
+ }
3251
4461
  }
3252
4462
 
3253
- class SubcommandGroupBuilder extends CommandOptionBuilder {
3254
- constructor() {
3255
- super(ApplicationCommandOptionType.SubcommandGroup);
3256
- }
3257
- addSubcommand(configure) {
3258
- const options = this.data.options ?? [];
3259
- if (options.length >= 25)
3260
- throw new RangeError("A subcommand group cannot contain more than 25 subcommands.");
3261
- const payload = configure(new SubcommandBuilder).toJSON();
3262
- if (options.some((existing) => existing.name === payload.name))
3263
- throw new RangeError(`Duplicate subcommand name: ${String(payload.name)}.`);
3264
- if (payload.type !== ApplicationCommandOptionType.Subcommand)
3265
- throw new TypeError("Subcommand group children must be subcommands.");
3266
- options.push(payload);
3267
- this.data.options = options;
4463
+ class ContentInventoryEntryBuilder {
4464
+ #id = "";
4465
+ setId(id) {
4466
+ validateText(id, 100, "Content inventory entry ID");
4467
+ this.#id = id;
3268
4468
  return this;
3269
4469
  }
4470
+ toJSON() {
4471
+ return {
4472
+ type: ComponentType.ContentInventoryEntry,
4473
+ id: this.#id
4474
+ };
4475
+ }
3270
4476
  }
3271
- function validateName(value, field) {
3272
- if (!/^[\p{L}\p{N}_-]{1,32}$/u.test(value) || value !== value.toLowerCase())
3273
- throw new RangeError(`${field} must contain 1-32 lowercase letters, numbers, underscores, or hyphens.`);
3274
- }
3275
- function validateText2(value, field, max) {
3276
- if (typeof value !== "string" || !value.trim() || value.length > max)
3277
- throw new RangeError(`${field} must contain 1-${max} characters.`);
4477
+ function validateText(value, max, field) {
4478
+ if (typeof value !== "string")
4479
+ throw new TypeError(`${field} must be a string.`);
4480
+ if (!value.trim())
4481
+ throw new RangeError(`${field} must be a non-empty string.`);
4482
+ if (value.length > max)
4483
+ throw new RangeError(`${field} cannot exceed ${max} characters.`);
3278
4484
  }
3279
- function validateIntegerRange(value, minimum, maximum, field) {
3280
- if (!Number.isInteger(value) || value < minimum || value > maximum)
3281
- throw new RangeError(`${field} must be an integer between ${minimum} and ${maximum}.`);
4485
+ function validateCount(value, field, min, max = 25) {
4486
+ if (!Number.isInteger(value) || value < min || value > max)
4487
+ throw new RangeError(`${field} must be an integer between ${min} and ${max}.`);
3282
4488
  }
3283
- function validateNumberRange(value, minimum, maximum, field, integerOnly = true) {
3284
- if (!Number.isFinite(value) || integerOnly && !Number.isInteger(value) || value < minimum || value > maximum)
3285
- throw new RangeError(`${field} must be ${integerOnly ? "an integer" : "a number"} between ${minimum} and ${maximum}.`);
4489
+ function validateLength(value, field, max = 4000) {
4490
+ if (!Number.isInteger(value) || value < 0 || value > max)
4491
+ throw new RangeError(`${field} must be an integer between 0 and ${max}.`);
3286
4492
  }
3287
- // packages/builders/src/attachment.ts
3288
- import { readFile } from "fs/promises";
3289
- import { basename } from "path";
4493
+ // packages/builders/src/commands.ts
4494
+ var ApplicationCommandOptionType2 = {
4495
+ Subcommand: 1,
4496
+ SubcommandGroup: 2,
4497
+ String: 3,
4498
+ Integer: 4,
4499
+ Boolean: 5,
4500
+ User: 6,
4501
+ Channel: 7,
4502
+ Role: 8,
4503
+ Mentionable: 9,
4504
+ Number: 10,
4505
+ Attachment: 11
4506
+ };
3290
4507
 
3291
- class AttachmentBuilder {
3292
- name;
3293
- description;
3294
- file;
3295
- constructor(file, data) {
3296
- this.file = file;
3297
- if (typeof data === "string") {
3298
- this.name = data;
3299
- } else {
3300
- this.name = data?.name ?? (typeof file === "string" ? basename(file) : "file.bin");
3301
- this.description = data?.description;
3302
- }
3303
- }
4508
+ class SlashCommandBuilder {
4509
+ #data = { type: 1 };
3304
4510
  setName(name) {
3305
- this.name = name;
4511
+ validateName(name, "Command name");
4512
+ this.#data.name = name;
3306
4513
  return this;
3307
4514
  }
3308
4515
  setDescription(description) {
3309
- this.description = description;
4516
+ validateText2(description, "Command description", 100);
4517
+ this.#data.description = description;
3310
4518
  return this;
3311
4519
  }
3312
- setFile(file) {
3313
- this.file = file;
4520
+ setDMPermission(enabled) {
4521
+ this.#data.dm_permission = enabled;
3314
4522
  return this;
3315
4523
  }
3316
- async toBuffer() {
3317
- if (typeof this.file === "string") {
3318
- const buffer = await readFile(this.file);
3319
- return new Uint8Array(buffer);
3320
- }
3321
- if (this.file instanceof Uint8Array)
3322
- return this.file;
3323
- if (this.file instanceof ArrayBuffer)
3324
- return new Uint8Array(this.file);
3325
- if (this.file instanceof Blob) {
3326
- const buf = await this.file.arrayBuffer();
3327
- return new Uint8Array(buf);
3328
- }
3329
- if (typeof Buffer !== "undefined" && Buffer.isBuffer(this.file)) {
3330
- return new Uint8Array(this.file);
3331
- }
3332
- return new Uint8Array;
3333
- }
3334
- }
3335
- // packages/core/src/collector.ts
3336
- import { EventEmitter } from "events";
3337
-
3338
- class Collector extends EventEmitter {
3339
- collected = new Map;
3340
- options;
3341
- ended = false;
3342
- endReason;
3343
- totalProcessed = 0;
3344
- #timeoutTimer;
3345
- constructor(options = {}) {
3346
- super();
3347
- this.options = options;
3348
- if (options.time && options.time > 0) {
3349
- this.#timeoutTimer = setTimeout(() => {
3350
- this.stop("time");
3351
- }, options.time);
3352
- }
4524
+ setNSFW(nsfw = true) {
4525
+ this.#data.nsfw = nsfw;
4526
+ return this;
3353
4527
  }
3354
- async handle(key, item) {
3355
- if (this.ended)
3356
- return false;
3357
- this.totalProcessed++;
3358
- if (this.options.filter) {
3359
- const passed = await this.options.filter(item);
3360
- if (!passed)
3361
- return false;
3362
- }
3363
- this.collected.set(key, item);
3364
- this.emit("collect", item);
3365
- if (this.options.max && this.collected.size >= this.options.max) {
3366
- this.stop("limit");
3367
- return true;
3368
- }
3369
- if (this.options.maxProcessed && this.totalProcessed >= this.options.maxProcessed) {
3370
- this.stop("processedLimit");
3371
- return true;
3372
- }
3373
- return true;
4528
+ setNsfw(nsfw = true) {
4529
+ return this.setNSFW(nsfw);
3374
4530
  }
3375
- stop(reason = "user") {
3376
- if (this.ended)
3377
- return;
3378
- this.ended = true;
3379
- this.endReason = reason;
3380
- if (this.#timeoutTimer)
3381
- clearTimeout(this.#timeoutTimer);
3382
- this.emit("end", this.collected, reason);
3383
- this.removeAllListeners();
3384
- }
3385
- next() {
3386
- return new Promise((resolve, reject) => {
3387
- if (this.ended) {
3388
- return reject(new Error(`Collector already ended: ${this.endReason ?? "unknown"}`));
3389
- }
3390
- this.once("collect", (item) => {
3391
- resolve(item);
3392
- });
3393
- this.once("end", (_collected, reason) => {
3394
- reject(new Error(`Collector ended before item was collected: ${reason}`));
3395
- });
3396
- });
4531
+ setDefaultMemberPermissions(permissions) {
4532
+ this.#data.default_member_permissions = permissions === null ? null : BigInt(permissions).toString();
4533
+ return this;
3397
4534
  }
3398
- }
3399
-
3400
- // packages/core/src/index.ts
3401
- class EventEmitter2 {
3402
- #listeners = new Map;
3403
- on(event, listener) {
3404
- if (typeof listener !== "function")
3405
- throw new TypeError("Event listener must be a function.");
3406
- let listeners = this.#listeners.get(event);
3407
- if (!listeners)
3408
- this.#listeners.set(event, listeners = new Set);
3409
- listeners.add(listener);
4535
+ setIntegrationTypes(...types) {
4536
+ this.#data.integration_types = [...types];
3410
4537
  return this;
3411
4538
  }
3412
- once(event, listener) {
3413
- const wrapped = (...args) => {
3414
- this.off(event, wrapped);
3415
- return listener(...args);
3416
- };
3417
- return this.on(event, wrapped);
4539
+ addStringOption(configure) {
4540
+ return this.addOption(configure(new StringOptionBuilder));
4541
+ }
4542
+ addIntegerOption(configure) {
4543
+ return this.addOption(configure(new IntegerOptionBuilder));
4544
+ }
4545
+ addNumberOption(configure) {
4546
+ return this.addOption(configure(new NumberOptionBuilder));
3418
4547
  }
3419
- off(event, listener) {
3420
- this.#listeners.get(event)?.delete(listener);
3421
- return this;
4548
+ addBooleanOption(configure) {
4549
+ return this.addOption(configure(new BooleanOptionBuilder));
3422
4550
  }
3423
- removeAllListeners(event) {
3424
- if (event === undefined)
3425
- this.#listeners.clear();
3426
- else
3427
- this.#listeners.delete(event);
3428
- return this;
4551
+ addUserOption(configure) {
4552
+ return this.addOption(configure(new UserOptionBuilder));
3429
4553
  }
3430
- emit(event, ...args) {
3431
- const listeners = this.#listeners.get(event);
3432
- if (!listeners?.size)
3433
- return false;
3434
- for (const listener of [...listeners]) {
3435
- try {
3436
- const result = listener(...args);
3437
- if (result && typeof result.then === "function")
3438
- Promise.resolve(result).catch((error) => this.#handleError(event, error));
3439
- } catch (error) {
3440
- this.#handleError(event, error);
3441
- }
3442
- }
3443
- return true;
4554
+ addChannelOption(configure) {
4555
+ return this.addOption(configure(new ChannelOptionBuilder));
3444
4556
  }
3445
- #handleError(event, error) {
3446
- if (event === "error")
3447
- return;
3448
- const normalized = error instanceof Error ? error : new Error(String(error), { cause: error });
3449
- for (const listener of [
3450
- ...this.#listeners.get("error") ?? []
3451
- ]) {
3452
- try {
3453
- listener(normalized);
3454
- } catch {}
3455
- }
4557
+ addRoleOption(configure) {
4558
+ return this.addOption(configure(new RoleOptionBuilder));
3456
4559
  }
3457
- }
3458
-
3459
- class Client extends EventEmitter2 {
3460
- options;
3461
- rest;
3462
- users;
3463
- guilds;
3464
- channels;
3465
- application;
3466
- get ws() {
3467
- return this.#gateway;
4560
+ addMentionableOption(configure) {
4561
+ return this.addOption(configure(new MentionableOptionBuilder));
3468
4562
  }
3469
- get gateway() {
3470
- return this.#gateway;
4563
+ addAttachmentOption(configure) {
4564
+ return this.addOption(configure(new AttachmentOptionBuilder));
3471
4565
  }
3472
- user;
3473
- readyAt;
3474
- state = "idle";
3475
- get uptime() {
3476
- return this.readyAt ? Date.now() - this.readyAt.getTime() : null;
4566
+ addSubcommand(configure) {
4567
+ return this.addOption(configure(new SubcommandBuilder));
3477
4568
  }
3478
- #gateway;
3479
- #resourceContext;
3480
- constructor(options) {
3481
- super();
3482
- this.options = options;
3483
- if (!options.token?.trim())
3484
- throw new TypeError("Client token is required.");
3485
- this.rest = new REST({ token: options.token, ...options.rest });
3486
- this.users = new UserManager(this.rest);
3487
- this.guilds = new GuildManager(this.rest);
3488
- this.channels = new ChannelManager(this.rest);
3489
- const placeholderAppCommands = new ApplicationCommandManager(this.rest, "0");
3490
- this.application = { commands: placeholderAppCommands };
3491
- this.#resourceContext = {
3492
- sendMessage: (channelId, options2) => this.channels.send(channelId, options2),
3493
- editMessage: (channelId, messageId, options2) => this.channels.editMessage(channelId, messageId, options2),
3494
- deleteMessage: (channelId, messageId) => this.channels.deleteMessage(channelId, messageId),
3495
- crosspostMessage: (channelId, messageId) => this.channels.crosspostMessage(channelId, messageId)
3496
- };
3497
- this.#gateway = new Gateway({
3498
- token: options.token,
3499
- intents: options.intents,
3500
- ...options.gateway
3501
- });
3502
- this.#gateway.on("READY", (data) => {
3503
- const ready = data;
3504
- this.user = ready.user;
3505
- this.users.set(this.user.id, new User(this.user));
3506
- this.readyAt = new Date;
3507
- this.state = "ready";
3508
- const appId = ready.application?.id ?? this.user.id;
3509
- this.application.commands = new ApplicationCommandManager(this.rest, appId);
3510
- this.emit("ready", this.user);
3511
- });
3512
- this.#gateway.on("open", () => this.emit("open"));
3513
- this.#gateway.on("close", (data) => {
3514
- if (this.state !== "destroyed")
3515
- this.state = "idle";
3516
- this.emit("close", data);
3517
- });
3518
- this.#gateway.on("MESSAGE_CREATE", (data) => {
3519
- const message = new Message(data, this.#resourceContext);
3520
- this.channels.set(message.channelId, message.channel);
3521
- this.users.set(message.author.id, message.author);
3522
- this.emit("messageCreate", message);
3523
- });
3524
- this.#gateway.on("MESSAGE_UPDATE", (data) => {
3525
- const message = new Message(data, this.#resourceContext);
3526
- this.channels.set(message.channelId, message.channel);
3527
- this.users.set(message.author.id, message.author);
3528
- this.emit("messageUpdate", message);
3529
- });
3530
- this.#gateway.on("MESSAGE_DELETE", (data) => this.emit("messageDelete", data));
3531
- this.#gateway.on("MESSAGE_DELETE_BULK", (data) => this.emit("messageDeleteBulk", data));
3532
- this.#gateway.on("GUILD_CREATE", (data) => {
3533
- const guild = new Guild(data);
3534
- this.guilds.set(guild.id, guild);
3535
- const payload = data;
3536
- for (const member of payload.members ?? [])
3537
- this.users.set(member.user.id, new User(member.user));
3538
- for (const channelData of [
3539
- ...payload.channels ?? [],
3540
- ...payload.threads ?? []
3541
- ]) {
3542
- const channel = new Channel(channelData, this.#resourceContext);
3543
- this.channels.set(channel.id, channel);
3544
- }
3545
- this.emit("guildCreate", data);
3546
- });
3547
- this.#gateway.on("GUILD_UPDATE", (data) => {
3548
- const guild = new Guild(data);
3549
- this.guilds.update(guild);
3550
- this.emit("guildUpdate", data);
3551
- });
3552
- this.#gateway.on("GUILD_DELETE", (data) => {
3553
- const payload = data;
3554
- if (!payload.unavailable)
3555
- this.guilds.delete(payload.id);
3556
- this.emit("guildDelete", payload);
3557
- });
3558
- this.#gateway.on("CHANNEL_CREATE", (data) => {
3559
- const channel = new Channel(data, this.#resourceContext);
3560
- this.channels.update(channel);
3561
- this.emit("channelCreate", channel);
3562
- });
3563
- this.#gateway.on("CHANNEL_UPDATE", (data) => {
3564
- const channel = new Channel(data, this.#resourceContext);
3565
- this.channels.update(channel);
3566
- this.emit("channelUpdate", channel);
3567
- });
3568
- this.#gateway.on("CHANNEL_DELETE", (data) => {
3569
- const payload = data;
3570
- this.channels.delete(payload.id);
3571
- this.emit("channelDelete", payload);
3572
- });
3573
- this.#gateway.on("THREAD_CREATE", (data) => {
3574
- const channel = new Channel(data, this.#resourceContext);
3575
- this.channels.update(channel);
3576
- this.emit("threadCreate", channel);
3577
- });
3578
- this.#gateway.on("THREAD_UPDATE", (data) => {
3579
- const channel = new Channel(data, this.#resourceContext);
3580
- this.channels.update(channel);
3581
- this.emit("threadUpdate", channel);
3582
- });
3583
- this.#gateway.on("THREAD_DELETE", (data) => {
3584
- const payload = data;
3585
- this.channels.delete(payload.id);
3586
- this.emit("threadDelete", payload);
3587
- });
3588
- this.#gateway.on("GUILD_MEMBER_ADD", (data) => {
3589
- const member = data;
3590
- this.users.set(member.user.id, new User(member.user));
3591
- this.emit("guildMemberAdd", member);
3592
- });
3593
- this.#gateway.on("GUILD_MEMBER_UPDATE", (data) => {
3594
- const member = data;
3595
- this.users.set(member.user.id, new User(member.user));
3596
- this.emit("guildMemberUpdate", member);
3597
- });
3598
- this.#gateway.on("GUILD_MEMBER_REMOVE", (data) => this.emit("guildMemberRemove", data));
3599
- this.#gateway.on("MESSAGE_REACTION_ADD", (data) => this.emit("messageReactionAdd", data));
3600
- this.#gateway.on("MESSAGE_REACTION_REMOVE", (data) => this.emit("messageReactionRemove", data));
3601
- this.#gateway.on("MESSAGE_REACTION_REMOVE_ALL", (data) => this.emit("messageReactionRemoveAll", data));
3602
- this.#gateway.on("INTERACTION_CREATE", (data) => this.emit("interactionCreate", createInteraction(this, data)));
3603
- this.#gateway.on("GUILD_ROLE_CREATE", (data) => this.emit("guildRoleCreate", data));
3604
- this.#gateway.on("GUILD_ROLE_UPDATE", (data) => this.emit("guildRoleUpdate", data));
3605
- this.#gateway.on("GUILD_ROLE_DELETE", (data) => this.emit("guildRoleDelete", data));
3606
- this.#gateway.on("GUILD_BAN_ADD", (data) => this.emit("guildBanAdd", data));
3607
- this.#gateway.on("GUILD_BAN_REMOVE", (data) => this.emit("guildBanRemove", data));
3608
- this.#gateway.on("GUILD_EMOJIS_UPDATE", (data) => this.emit("guildEmojisUpdate", data));
3609
- for (const event of [
3610
- "READY",
3611
- "MESSAGE_CREATE",
3612
- "MESSAGE_UPDATE",
3613
- "MESSAGE_DELETE",
3614
- "MESSAGE_DELETE_BULK",
3615
- "GUILD_CREATE",
3616
- "GUILD_UPDATE",
3617
- "GUILD_DELETE",
3618
- "CHANNEL_CREATE",
3619
- "CHANNEL_UPDATE",
3620
- "CHANNEL_DELETE",
3621
- "THREAD_CREATE",
3622
- "THREAD_UPDATE",
3623
- "THREAD_DELETE",
3624
- "GUILD_MEMBER_ADD",
3625
- "GUILD_MEMBER_UPDATE",
3626
- "GUILD_MEMBER_REMOVE",
3627
- "MESSAGE_REACTION_ADD",
3628
- "MESSAGE_REACTION_REMOVE",
3629
- "MESSAGE_REACTION_REMOVE_ALL",
3630
- "INTERACTION_CREATE",
3631
- "GUILD_ROLE_CREATE",
3632
- "GUILD_ROLE_UPDATE",
3633
- "GUILD_ROLE_DELETE",
3634
- "GUILD_BAN_ADD",
3635
- "GUILD_BAN_REMOVE",
3636
- "GUILD_EMOJIS_UPDATE"
3637
- ])
3638
- this.#gateway.on(event, (data) => this.emit("raw", { event, data }));
3639
- this.#gateway.on("error", (data) => this.emit("error", data));
4569
+ addSubcommandGroup(configure) {
4570
+ return this.addOption(configure(new SubcommandGroupBuilder));
3640
4571
  }
3641
- isReady() {
3642
- return this.state === "ready" && this.user !== undefined && this.readyAt !== undefined;
4572
+ toJSON() {
4573
+ return structuredClone(this.#data);
3643
4574
  }
3644
- async login() {
3645
- if (this.state === "destroyed")
3646
- throw new Error("Cannot login a destroyed client.");
3647
- if (this.state === "connecting" || this.state === "ready")
3648
- return;
3649
- this.state = "connecting";
3650
- try {
3651
- this.user = await this.rest.get(Routes.user());
3652
- this.users.set(this.user.id, new User(this.user));
3653
- await this.#gateway.connect();
3654
- } catch (error) {
3655
- this.state = "idle";
3656
- throw error;
3657
- }
4575
+ addOption(option) {
4576
+ const options = this.#data.options ?? [];
4577
+ if (options.length >= 25)
4578
+ throw new RangeError("An application command cannot contain more than 25 options.");
4579
+ const payload = option.toJSON();
4580
+ if (options.some((existing) => existing.name === payload.name))
4581
+ throw new RangeError(`Duplicate option name: ${String(payload.name)}.`);
4582
+ if (payload.required === true && options.some((existing) => existing.required !== true))
4583
+ throw new RangeError("Required application command options must be placed before optional options.");
4584
+ options.push(payload);
4585
+ this.#data.options = options;
4586
+ return this;
3658
4587
  }
3659
- destroy() {
3660
- if (this.state === "destroyed")
3661
- return;
3662
- this.#gateway.close();
3663
- this.users.clear();
3664
- this.guilds.clear();
3665
- this.channels.clear();
3666
- this.state = "destroyed";
3667
- this.readyAt = undefined;
3668
- this.user = undefined;
4588
+ }
4589
+
4590
+ class CommandOptionBuilder {
4591
+ data;
4592
+ constructor(type) {
4593
+ this.data = { type };
3669
4594
  }
3670
- postInteractionResponse(id, token, response) {
3671
- return this.rest.post(Routes.interactionCallback(id, token), response.toJSON());
4595
+ setName(name) {
4596
+ validateName(name, "Option name");
4597
+ this.data.name = name;
4598
+ return this;
3672
4599
  }
3673
- editInteractionReply(token, data) {
3674
- if (!this.user?.id)
3675
- throw new Error("Client user is unavailable; login is required.");
3676
- return this.rest.patch(Routes.interactionOriginalResponse(this.user.id, token), data);
4600
+ setDescription(description) {
4601
+ validateText2(description, "Option description", 100);
4602
+ this.data.description = description;
4603
+ return this;
3677
4604
  }
3678
- async deleteInteractionReply(token) {
3679
- if (!this.user?.id)
3680
- throw new Error("Client user is unavailable; login is required.");
3681
- await this.rest.delete(Routes.interactionOriginalResponse(this.user.id, token));
4605
+ setRequired(required = true) {
4606
+ this.data.required = required;
4607
+ return this;
3682
4608
  }
3683
- setPresence(presence) {
3684
- return this.#gateway.setPresence(presence);
4609
+ setAutocomplete(enabled = true) {
4610
+ this.data.autocomplete = enabled;
4611
+ return this;
3685
4612
  }
3686
- followUpInteraction(token, data) {
3687
- if (!this.user?.id)
3688
- throw new Error("Client user is unavailable; login is required.");
3689
- return this.rest.post(Routes.webhook(this.user.id, token), data);
4613
+ toJSON() {
4614
+ return structuredClone(this.data);
3690
4615
  }
3691
4616
  }
3692
- // packages/formatters/src/index.ts
3693
- function userMention(id) {
3694
- return `<@${validateSnowflake(id, "User ID")}>`;
3695
- }
3696
- function channelMention(id) {
3697
- return `<#${validateSnowflake(id, "Channel ID")}>`;
3698
- }
3699
- function roleMention(id) {
3700
- return `<@&${validateSnowflake(id, "Role ID")}>`;
3701
- }
3702
- function timestamp(unixSeconds, style) {
3703
- if (!Number.isFinite(unixSeconds))
3704
- throw new TypeError("Timestamp must be a finite Unix timestamp.");
3705
- if (style !== undefined && !/^[tTdDfFR]$/.test(style))
3706
- throw new RangeError("Invalid Discord timestamp style.");
3707
- return `<t:${Math.floor(unixSeconds)}${style ? `:${style}` : ""}>`;
3708
- }
3709
- function escapeMarkdown(value) {
3710
- return value.replace(/[\\*_`~|>]/g, "\\$&");
3711
- }
3712
- function validateSnowflake(id, field) {
3713
- const len = id.length;
3714
- if (len < 1 || len > 20) {
3715
- throw new TypeError(`${field} must be a valid Discord snowflake.`);
4617
+
4618
+ class StringOptionBuilder extends CommandOptionBuilder {
4619
+ constructor() {
4620
+ super(ApplicationCommandOptionType2.String);
3716
4621
  }
3717
- for (let i = 0;i < len; i++) {
3718
- const code = id.charCodeAt(i);
3719
- if (code < 48 || code > 57) {
3720
- throw new TypeError(`${field} must be a valid Discord snowflake.`);
4622
+ addChoices(...choices) {
4623
+ const current = this.data.choices ?? [];
4624
+ if (!choices.length)
4625
+ throw new TypeError("At least one choice is required.");
4626
+ if (this.data.autocomplete === true)
4627
+ throw new RangeError("Autocomplete options cannot define choices.");
4628
+ if (current.length + choices.length > 25)
4629
+ throw new RangeError("An option cannot contain more than 25 choices.");
4630
+ for (const choice of choices) {
4631
+ validateText2(choice.name, "Choice name", 100);
4632
+ validateText2(choice.value, "Choice value", 100);
3721
4633
  }
4634
+ this.data.choices = [
4635
+ ...current,
4636
+ ...choices.map((choice) => ({ ...choice }))
4637
+ ];
4638
+ return this;
3722
4639
  }
3723
- return id;
3724
- }
3725
- // packages/handlers/src/index.ts
3726
- class HandlerRegistry {
3727
- #handlers = new Map;
3728
- on(event, handler) {
3729
- let handlers = this.#handlers.get(event);
3730
- if (!handlers) {
3731
- handlers = new Set;
3732
- this.#handlers.set(event, handlers);
3733
- }
3734
- handlers.add(handler);
4640
+ setMinLength(value) {
4641
+ validateIntegerRange(value, 0, 6000, "min_length");
4642
+ this.data.min_length = value;
3735
4643
  return this;
3736
4644
  }
3737
- once(event, handler) {
3738
- const wrapped = (...args) => {
3739
- this.off(event, wrapped);
3740
- return handler(...args);
3741
- };
3742
- return this.on(event, wrapped);
4645
+ setMaxLength(value) {
4646
+ validateIntegerRange(value, 1, 6000, "max_length");
4647
+ if (this.data.min_length !== undefined && this.data.min_length > value)
4648
+ throw new RangeError("min_length cannot exceed max_length.");
4649
+ this.data.max_length = value;
4650
+ return this;
3743
4651
  }
3744
- off(event, handler) {
3745
- this.#handlers.get(event)?.delete(handler);
4652
+ }
4653
+
4654
+ class IntegerOptionBuilder extends CommandOptionBuilder {
4655
+ constructor() {
4656
+ super(ApplicationCommandOptionType2.Integer);
4657
+ }
4658
+ setMinValue(value) {
4659
+ validateNumberRange(value, -9007199254740991, 9007199254740991, "min_value", true);
4660
+ this.data.min_value = value;
3746
4661
  return this;
3747
4662
  }
3748
- async dispatch(event, ...args) {
3749
- for (const handler of this.#handlers.get(event) ?? [])
3750
- await handler(...args);
4663
+ setMaxValue(value) {
4664
+ validateNumberRange(value, -9007199254740991, 9007199254740991, "max_value", true);
4665
+ if (this.data.min_value !== undefined && this.data.min_value > value)
4666
+ throw new RangeError("min_value cannot exceed max_value.");
4667
+ this.data.max_value = value;
4668
+ return this;
3751
4669
  }
3752
- emit(event, ...args) {
3753
- return this.dispatch(event, ...args);
4670
+ setAutocomplete(enabled = true) {
4671
+ if (enabled && Array.isArray(this.data.choices) && this.data.choices.length)
4672
+ throw new RangeError("Autocomplete options cannot define choices.");
4673
+ this.data.autocomplete = enabled;
4674
+ return this;
4675
+ }
4676
+ addChoices(...choices) {
4677
+ const current = this.data.choices ?? [];
4678
+ if (!choices.length)
4679
+ throw new TypeError("At least one choice is required.");
4680
+ if (this.data.autocomplete === true)
4681
+ throw new RangeError("Autocomplete options cannot define choices.");
4682
+ if (current.length + choices.length > 25)
4683
+ throw new RangeError("An option cannot contain more than 25 choices.");
4684
+ this.data.choices = [...current, ...choices];
4685
+ return this;
3754
4686
  }
3755
4687
  }
3756
- // packages/sharding/src/bus.ts
3757
- class ShardBus {
3758
- #channel;
3759
- #handlers = new Map;
3760
- #shardId;
3761
- #namespace;
3762
- channelName;
3763
- #counter = 0;
3764
- constructor(shardId, channelName) {
3765
- if (!Number.isInteger(shardId) || shardId < 0)
3766
- throw new RangeError("Shard ID must be a non-negative integer.");
3767
- if (!channelName?.trim())
3768
- throw new TypeError("An application-specific shard channel name is required.");
3769
- this.#shardId = shardId;
3770
- this.#namespace = channelName.trim();
3771
- this.channelName = this.#namespace;
3772
- this.#channel = new BroadcastChannel(this.channelName);
3773
- this.#channel.addEventListener("message", (event) => this.#dispatch(event.data));
4688
+
4689
+ class NumberOptionBuilder extends CommandOptionBuilder {
4690
+ constructor() {
4691
+ super(ApplicationCommandOptionType2.Number);
3774
4692
  }
3775
- on(type, handler) {
3776
- if (!type.trim() || typeof handler !== "function")
3777
- throw new TypeError("Shard message type and handler are required.");
3778
- let handlers = this.#handlers.get(type);
3779
- if (!handlers)
3780
- this.#handlers.set(type, handlers = new Set);
3781
- handlers.add(handler);
4693
+ setMinValue(value) {
4694
+ validateNumberRange(value, -9007199254740991, 9007199254740991, "min_value", false);
4695
+ this.data.min_value = value;
3782
4696
  return this;
3783
4697
  }
3784
- off(type, handler) {
3785
- this.#handlers.get(type)?.delete(handler);
4698
+ setMaxValue(value) {
4699
+ validateNumberRange(value, -9007199254740991, 9007199254740991, "max_value", false);
4700
+ if (this.data.min_value !== undefined && this.data.min_value > value)
4701
+ throw new RangeError("min_value cannot exceed max_value.");
4702
+ this.data.max_value = value;
3786
4703
  return this;
3787
4704
  }
3788
- send(target, type, data) {
3789
- if (!Number.isInteger(target) || target < 0)
3790
- throw new RangeError("Shard target must be a non-negative integer.");
3791
- return this.#publish(target, type, data);
4705
+ setAutocomplete(enabled = true) {
4706
+ if (enabled && Array.isArray(this.data.choices) && this.data.choices.length)
4707
+ throw new RangeError("Autocomplete options cannot define choices.");
4708
+ this.data.autocomplete = enabled;
4709
+ return this;
3792
4710
  }
3793
- broadcast(type, data) {
3794
- return this.#publish(null, type, data);
4711
+ addChoices(...choices) {
4712
+ const current = this.data.choices ?? [];
4713
+ if (!choices.length)
4714
+ throw new TypeError("At least one choice is required.");
4715
+ if (this.data.autocomplete === true)
4716
+ throw new RangeError("Autocomplete options cannot define choices.");
4717
+ if (current.length + choices.length > 25)
4718
+ throw new RangeError("An option cannot contain more than 25 choices.");
4719
+ this.data.choices = [...current, ...choices];
4720
+ return this;
3795
4721
  }
3796
- close() {
3797
- this.#channel.close();
3798
- this.#handlers.clear();
4722
+ }
4723
+
4724
+ class BooleanOptionBuilder extends CommandOptionBuilder {
4725
+ constructor() {
4726
+ super(ApplicationCommandOptionType2.Boolean);
3799
4727
  }
3800
- #publish(target, type, data) {
3801
- if (!type.trim())
3802
- throw new TypeError("Shard message type is required.");
3803
- const id = `${this.#namespace}:${this.#shardId}:${++this.#counter}`;
3804
- this.#channel.postMessage({
3805
- source: this.#shardId,
3806
- target,
3807
- type,
3808
- data,
3809
- id
3810
- });
3811
- return id;
4728
+ }
4729
+
4730
+ class UserOptionBuilder extends CommandOptionBuilder {
4731
+ constructor() {
4732
+ super(ApplicationCommandOptionType2.User);
3812
4733
  }
3813
- #dispatch(message) {
3814
- if (!message || typeof message !== "object" || typeof message.type !== "string")
3815
- return;
3816
- if (message.source === this.#shardId || message.target !== null && message.target !== this.#shardId)
3817
- return;
3818
- for (const handler of this.#handlers.get(message.type) ?? []) {
3819
- try {
3820
- const result = handler(message);
3821
- if (result && typeof result.then === "function")
3822
- Promise.resolve(result).catch(() => {
3823
- return;
3824
- });
3825
- } catch {}
3826
- }
4734
+ }
4735
+
4736
+ class RoleOptionBuilder extends CommandOptionBuilder {
4737
+ constructor() {
4738
+ super(ApplicationCommandOptionType2.Role);
3827
4739
  }
3828
4740
  }
3829
4741
 
3830
- // packages/sharding/src/index.ts
3831
- class ShardManager {
3832
- shards = new Map;
3833
- get shardCount() {
3834
- return this.shards.size;
4742
+ class MentionableOptionBuilder extends CommandOptionBuilder {
4743
+ constructor() {
4744
+ super(ApplicationCommandOptionType2.Mentionable);
3835
4745
  }
3836
- #options;
3837
- #resolved = false;
3838
- #destroyed = false;
3839
- constructor(options) {
3840
- if (!options.token?.trim())
3841
- throw new TypeError("A Discord bot token is required.");
3842
- if (!Number.isInteger(options.intents) || options.intents < 0)
3843
- throw new TypeError("Gateway intents must be a non-negative integer.");
3844
- const count = options.shardCount === "auto" || options.shardCount === undefined ? 1 : options.shardCount;
3845
- if (!Number.isInteger(count) || count < 1)
3846
- throw new RangeError("Shard count must be a positive integer.");
3847
- this.#options = { ...options };
3848
- if (options.shardCount !== "auto")
3849
- this.#initialize(count);
4746
+ }
4747
+
4748
+ class AttachmentOptionBuilder extends CommandOptionBuilder {
4749
+ constructor() {
4750
+ super(ApplicationCommandOptionType2.Attachment);
3850
4751
  }
3851
- async fetchRecommendedShardCount() {
3852
- const response = await fetch("https://discord.com/api/v10/gateway/bot", {
3853
- headers: {
3854
- Authorization: `Bot ${this.#options.token}`,
3855
- "User-Agent": "Lunibee/0.1.0"
3856
- }
3857
- });
3858
- if (!response.ok)
3859
- throw new Error(`Gateway discovery failed with status ${response.status}`);
3860
- const data = await response.json();
3861
- if (typeof data.shards !== "number" || !Number.isInteger(data.shards) || data.shards < 1)
3862
- throw new Error("Gateway discovery returned an invalid shard count.");
3863
- return data.shards;
4752
+ }
4753
+
4754
+ class ChannelOptionBuilder extends CommandOptionBuilder {
4755
+ constructor() {
4756
+ super(ApplicationCommandOptionType2.Channel);
3864
4757
  }
3865
- async connect() {
3866
- await this.#ensureInitialized();
3867
- for (const [id, shard] of this.shards) {
3868
- try {
3869
- await shard.connect();
3870
- } catch (error) {
3871
- this.destroy();
3872
- throw new Error(`Failed to connect shard ${id}.`, { cause: error });
3873
- }
3874
- if (id + 1 < this.shardCount && this.#options.spawnDelay && this.#options.spawnDelay > 0)
3875
- await Bun.sleep(this.#options.spawnDelay);
3876
- }
4758
+ addChannelTypes(...types) {
4759
+ if (types.some((type) => !Number.isInteger(type) || type < 0))
4760
+ throw new RangeError("Channel types must be non-negative integers.");
4761
+ this.data.channel_types = [...new Set(types)];
4762
+ return this;
3877
4763
  }
3878
- destroy() {
3879
- for (const shard of this.shards.values())
3880
- shard.close();
3881
- this.shards.clear();
3882
- this.#resolved = false;
3883
- this.#destroyed = true;
4764
+ }
4765
+
4766
+ class SubcommandBuilder extends CommandOptionBuilder {
4767
+ constructor() {
4768
+ super(ApplicationCommandOptionType2.Subcommand);
4769
+ }
4770
+ addStringOption(configure) {
4771
+ return this.addChildOption(configure(new StringOptionBuilder));
4772
+ }
4773
+ addIntegerOption(configure) {
4774
+ return this.addChildOption(configure(new IntegerOptionBuilder));
4775
+ }
4776
+ addNumberOption(configure) {
4777
+ return this.addChildOption(configure(new NumberOptionBuilder));
4778
+ }
4779
+ addBooleanOption(configure) {
4780
+ return this.addChildOption(configure(new BooleanOptionBuilder));
4781
+ }
4782
+ addUserOption(configure) {
4783
+ return this.addChildOption(configure(new UserOptionBuilder));
3884
4784
  }
3885
- getShardIdForGuild(guildId) {
3886
- const id = BigInt(guildId);
3887
- return Number((id >> 22n) % BigInt(this.shardCount || 1));
4785
+ addChannelOption(configure) {
4786
+ return this.addChildOption(configure(new ChannelOptionBuilder));
3888
4787
  }
3889
- get(id) {
3890
- return this.shards.get(id);
4788
+ addRoleOption(configure) {
4789
+ return this.addChildOption(configure(new RoleOptionBuilder));
3891
4790
  }
3892
- values() {
3893
- return [...this.shards].map(([id, gateway]) => ({ id, gateway }));
4791
+ addMentionableOption(configure) {
4792
+ return this.addChildOption(configure(new MentionableOptionBuilder));
3894
4793
  }
3895
- async#ensureInitialized() {
3896
- if (this.#resolved)
3897
- return;
3898
- if (this.#destroyed)
3899
- this.#destroyed = false;
3900
- const count = this.#options.shardCount === "auto" ? await this.fetchRecommendedShardCount() : this.#options.shardCount ?? 1;
3901
- this.#initialize(count);
4794
+ addAttachmentOption(configure) {
4795
+ return this.addChildOption(configure(new AttachmentOptionBuilder));
3902
4796
  }
3903
- #initialize(count) {
3904
- if (this.#resolved)
3905
- return;
3906
- for (let id = 0;id < count; id++)
3907
- this.shards.set(id, this.#createShard(id, count));
3908
- this.#resolved = true;
4797
+ addChildOption(option) {
4798
+ const options = this.data.options ?? [];
4799
+ if (options.length >= 25)
4800
+ throw new RangeError("A subcommand cannot contain more than 25 options.");
4801
+ const payload = option.toJSON();
4802
+ if (options.some((existing) => existing.name === payload.name))
4803
+ throw new RangeError(`Duplicate option name: ${String(payload.name)}.`);
4804
+ if (payload.required === true && options.some((existing) => existing.required !== true))
4805
+ throw new RangeError("Required subcommand options must be placed before optional options.");
4806
+ if (options.some((existing) => existing.type === ApplicationCommandOptionType2.Subcommand))
4807
+ throw new RangeError("Subcommands cannot contain nested subcommands.");
4808
+ options.push(payload);
4809
+ this.data.options = options;
4810
+ return this;
3909
4811
  }
3910
- #createShard(id, count) {
3911
- return new Gateway({
3912
- token: this.#options.token,
3913
- intents: this.#options.intents,
3914
- shardId: id,
3915
- shardCount: count,
3916
- reconnect: this.#options.reconnect ?? true
3917
- });
4812
+ }
4813
+
4814
+ class SubcommandGroupBuilder extends CommandOptionBuilder {
4815
+ constructor() {
4816
+ super(ApplicationCommandOptionType2.SubcommandGroup);
4817
+ }
4818
+ addSubcommand(configure) {
4819
+ const options = this.data.options ?? [];
4820
+ if (options.length >= 25)
4821
+ throw new RangeError("A subcommand group cannot contain more than 25 subcommands.");
4822
+ const payload = configure(new SubcommandBuilder).toJSON();
4823
+ if (options.some((existing) => existing.name === payload.name))
4824
+ throw new RangeError(`Duplicate subcommand name: ${String(payload.name)}.`);
4825
+ if (payload.type !== ApplicationCommandOptionType2.Subcommand)
4826
+ throw new TypeError("Subcommand group children must be subcommands.");
4827
+ options.push(payload);
4828
+ this.data.options = options;
4829
+ return this;
3918
4830
  }
3919
4831
  }
3920
- // packages/utils/src/index.ts
3921
- function sleep(ms) {
3922
- return new Promise((resolve) => setTimeout(resolve, ms));
4832
+ function validateName(value, field) {
4833
+ if (!/^[\p{L}\p{N}_-]{1,32}$/u.test(value) || value !== value.toLowerCase())
4834
+ throw new RangeError(`${field} must contain 1-32 lowercase letters, numbers, underscores, or hyphens.`);
3923
4835
  }
3924
- function randomInt(min, max) {
3925
- return Math.floor(Math.random() * (max - min + 1)) + min;
4836
+ function validateText2(value, field, max) {
4837
+ if (typeof value !== "string" || !value.trim() || value.length > max)
4838
+ throw new RangeError(`${field} must contain 1-${max} characters.`);
3926
4839
  }
3927
- function isSnowflake(value) {
3928
- return /^\d{16,22}$/.test(value);
4840
+ function validateIntegerRange(value, minimum, maximum, field) {
4841
+ if (!Number.isInteger(value) || value < minimum || value > maximum)
4842
+ throw new RangeError(`${field} must be an integer between ${minimum} and ${maximum}.`);
3929
4843
  }
3930
- // packages/voice/src/index.ts
3931
- var VoiceConnectionState;
3932
- ((VoiceConnectionState2) => {
3933
- VoiceConnectionState2["Disconnected"] = "disconnected";
3934
- VoiceConnectionState2["Connecting"] = "connecting";
3935
- VoiceConnectionState2["Connected"] = "connected";
3936
- VoiceConnectionState2["Destroyed"] = "destroyed";
3937
- })(VoiceConnectionState ||= {});
3938
-
3939
- class VoiceError extends Error {
3940
- constructor(message, options) {
3941
- super(message, options);
3942
- this.name = "VoiceError";
3943
- }
4844
+ function validateNumberRange(value, minimum, maximum, field, integerOnly = true) {
4845
+ if (!Number.isFinite(value) || integerOnly && !Number.isInteger(value) || value < minimum || value > maximum)
4846
+ throw new RangeError(`${field} must be ${integerOnly ? "an integer" : "a number"} between ${minimum} and ${maximum}.`);
3944
4847
  }
3945
- var SpeakingFlags = {
3946
- Microphone: 1,
3947
- Soundshare: 2,
3948
- Priority: 4
3949
- };
4848
+ // packages/builders/src/attachment.ts
4849
+ import { readFile } from "fs/promises";
4850
+ import { basename } from "path";
3950
4851
 
3951
- class VoiceConnection {
3952
- state = "disconnected" /* Disconnected */;
3953
- guildId;
3954
- channelId;
3955
- selfMute;
3956
- selfDeaf;
3957
- gateway;
3958
- udp;
3959
- #listeners = new Map;
3960
- constructor(options) {
3961
- const resolved = typeof options === "string" ? { guildId: options } : options;
3962
- if (!resolved.guildId?.trim()) {
3963
- throw new TypeError("A guild ID is required for a voice connection.");
4852
+ class AttachmentBuilder {
4853
+ name;
4854
+ description;
4855
+ file;
4856
+ constructor(file, data) {
4857
+ this.file = file;
4858
+ if (typeof data === "string") {
4859
+ this.name = data;
4860
+ } else {
4861
+ this.name = data?.name ?? (typeof file === "string" ? basename(file) : "file.bin");
4862
+ this.description = data?.description;
3964
4863
  }
3965
- this.guildId = resolved.guildId;
3966
- this.channelId = resolved.channelId;
3967
- this.selfMute = resolved.selfMute ?? false;
3968
- this.selfDeaf = resolved.selfDeaf ?? false;
3969
4864
  }
3970
- on(event, listener) {
3971
- if (typeof listener !== "function")
3972
- throw new TypeError("Voice listener must be a function.");
3973
- let listeners = this.#listeners.get(event);
3974
- if (!listeners)
3975
- this.#listeners.set(event, listeners = new Set);
3976
- listeners.add(listener);
4865
+ setName(name) {
4866
+ this.name = name;
3977
4867
  return this;
3978
4868
  }
3979
- off(event, listener) {
3980
- this.#listeners.get(event)?.delete(listener);
4869
+ setDescription(description) {
4870
+ this.description = description;
3981
4871
  return this;
3982
4872
  }
3983
- attachTransports(gateway, udp) {
3984
- this.assertUsable();
3985
- if (!gateway || !udp)
3986
- throw new TypeError("Both voice gateway and UDP transports are required.");
3987
- if (this.gateway || this.udp)
3988
- this.#closeTransports();
3989
- this.gateway = gateway;
3990
- this.udp = udp;
4873
+ setFile(file) {
4874
+ this.file = file;
3991
4875
  return this;
3992
4876
  }
3993
- connect() {
3994
- this.assertUsable();
3995
- if (this.state === "connected" /* Connected */)
3996
- return;
3997
- this.#transition("connecting" /* Connecting */);
3998
- if (this.state !== "connecting" /* Connecting */)
3999
- return;
4000
- this.#transition("connected" /* Connected */);
4001
- }
4002
- disconnect() {
4003
- if (this.state === "destroyed" /* Destroyed */)
4004
- return;
4005
- this.#closeTransports();
4006
- this.#transition("disconnected" /* Disconnected */);
4007
- }
4008
- destroy() {
4009
- if (this.state === "destroyed" /* Destroyed */)
4010
- return;
4011
- this.#closeTransports();
4012
- this.channelId = undefined;
4013
- this.#transition("destroyed" /* Destroyed */);
4014
- this.#listeners.clear();
4015
- }
4016
- setChannel(channelId) {
4017
- this.assertUsable();
4018
- if (!channelId?.trim())
4019
- throw new TypeError("A voice channel ID is required.");
4020
- this.channelId = channelId;
4021
- }
4022
- setSuppression(options) {
4023
- this.assertUsable();
4024
- if (options.selfMute !== undefined)
4025
- this.selfMute = options.selfMute;
4026
- if (options.selfDeaf !== undefined)
4027
- this.selfDeaf = options.selfDeaf;
4028
- }
4029
- setSpeaking(flags = SpeakingFlags.Microphone) {
4030
- this.assertUsable();
4031
- if (!this.gateway) {
4032
- throw new VoiceError("A voice gateway transport is required to change speaking state.");
4033
- }
4034
- this.gateway.send({ op: 5, d: { speaking: flags, delay: 0, ssrc: 0 } });
4035
- this.#emit("speaking", flags, 0);
4036
- }
4037
- #assertUsable() {
4038
- if (this.state === "destroyed" /* Destroyed */) {
4039
- throw new VoiceError("Voice connection has been destroyed.");
4040
- }
4041
- }
4042
- #closeTransports() {
4043
- try {
4044
- this.gateway?.close(1000, "Voice connection replaced or closed");
4045
- } catch (error) {
4046
- this.#emit("error", error instanceof VoiceError ? error : new VoiceError("Voice gateway cleanup failed.", { cause: error }));
4047
- }
4048
- try {
4049
- this.udp?.close();
4050
- } catch (error) {
4051
- this.#emit("error", error instanceof VoiceError ? error : new VoiceError("Voice UDP cleanup failed.", { cause: error }));
4877
+ async toBuffer() {
4878
+ if (typeof this.file === "string") {
4879
+ const buffer = await readFile(this.file);
4880
+ return new Uint8Array(buffer);
4052
4881
  }
4053
- this.gateway = undefined;
4054
- this.udp = undefined;
4055
- }
4056
- #transition(next) {
4057
- const previous = this.state;
4058
- this.state = next;
4059
- if (previous === next)
4060
- return;
4061
- for (const listener of this.#listeners.get("stateChange") ?? []) {
4062
- try {
4063
- listener(next, previous);
4064
- } catch (error) {
4065
- this.#emit("error", error instanceof VoiceError ? error : new VoiceError("Voice event listener failed.", { cause: error }));
4066
- }
4067
- if (this.state !== next && next !== "destroyed" /* Destroyed */)
4068
- return;
4882
+ if (this.file instanceof Uint8Array)
4883
+ return this.file;
4884
+ if (this.file instanceof ArrayBuffer)
4885
+ return new Uint8Array(this.file);
4886
+ if (this.file instanceof Blob) {
4887
+ const buf = await this.file.arrayBuffer();
4888
+ return new Uint8Array(buf);
4069
4889
  }
4070
- }
4071
- #emit(event, ...args) {
4072
- for (const listener of this.#listeners.get(event) ?? []) {
4073
- try {
4074
- listener(...args);
4075
- } catch {}
4890
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer(this.file)) {
4891
+ return new Uint8Array(this.file);
4076
4892
  }
4077
- }
4078
- assertUsable() {
4079
- this.#assertUsable();
4893
+ return new Uint8Array;
4080
4894
  }
4081
4895
  }
4082
4896
  export {
@@ -4097,13 +4911,18 @@ export {
4097
4911
  ChannelOptionBuilder,
4098
4912
  ChannelType,
4099
4913
  Client,
4914
+ ClientEvent,
4100
4915
  Collection,
4101
- Collector,
4102
4916
  CommandInteraction,
4917
+ CommandOptions,
4103
4918
  ComponentInteraction,
4104
4919
  ComponentType,
4920
+ ContainerBuilder,
4921
+ ContentInventoryEntryBuilder,
4922
+ Embed,
4105
4923
  EmbedBuilder,
4106
4924
  EntitySelectBuilder,
4925
+ FileComponentBuilder,
4107
4926
  Gateway,
4108
4927
  GatewayError,
4109
4928
  GatewayIntentBits,
@@ -4122,14 +4941,11 @@ export {
4122
4941
  InteractionResponseType,
4123
4942
  InteractionType,
4124
4943
  Manager,
4944
+ MediaGalleryBuilder,
4125
4945
  MentionableOptionBuilder,
4126
4946
  Message,
4127
- MessageCreateOptions,
4128
- MessageEditOptions,
4129
- MessageFetchOptions,
4130
4947
  MessageFlags,
4131
4948
  MessageManager,
4132
- MessageThreadOptions,
4133
4949
  ModalBuilder,
4134
4950
  ModalSubmitInteraction,
4135
4951
  NumberOptionBuilder,
@@ -4139,29 +4955,36 @@ export {
4139
4955
  PermissionSet,
4140
4956
  Permissions,
4141
4957
  PermissionsBitField,
4958
+ PremiumTier,
4142
4959
  REST,
4143
4960
  RESTError,
4144
- ReactionFetchOptions,
4145
4961
  ResourceManager,
4146
4962
  Role,
4147
4963
  RoleManager,
4148
4964
  RoleOptionBuilder,
4149
4965
  Routes,
4966
+ SectionBuilder,
4967
+ SeparatorBuilder,
4150
4968
  ShardBus,
4151
4969
  ShardManager,
4152
4970
  SlashCommandBuilder,
4153
4971
  SpeakingFlags,
4972
+ StickerFormatType,
4973
+ StickerType,
4154
4974
  StringOptionBuilder,
4155
4975
  StringSelectBuilder,
4156
4976
  SubcommandBuilder,
4157
4977
  SubcommandGroupBuilder,
4158
4978
  TextChannel,
4979
+ TextDisplayBuilder,
4159
4980
  TextInputBuilder,
4160
4981
  TextInputStyle,
4161
4982
  ThreadManager,
4983
+ ThumbnailBuilder,
4162
4984
  User,
4163
4985
  UserManager,
4164
4986
  UserOptionBuilder,
4987
+ VerificationLevel,
4165
4988
  VoiceConnection,
4166
4989
  VoiceConnectionState,
4167
4990
  VoiceError,
@@ -4179,4 +5002,4 @@ export {
4179
5002
  userMention
4180
5003
  };
4181
5004
 
4182
- //# debugId=13EFD1423B9A70DF64756E2164756E21
5005
+ //# debugId=0DD3C15D8E81668964756E2164756E21