lunibee 0.2.0 → 0.2.1

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.
package/dist/index.js CHANGED
@@ -396,6 +396,11 @@ class PermissionSet {
396
396
  toArray() {
397
397
  return Object.keys(Permission).filter((permission) => this.has(permission));
398
398
  }
399
+ static #renamed = {
400
+ ManageEmojisAndStickers: "ManageGuildExpressions",
401
+ ManageEmojis: "ManageGuildExpressions",
402
+ UseSlashCommands: "UseApplicationCommands"
403
+ };
399
404
  #resolve(permission) {
400
405
  if (typeof permission === "bigint")
401
406
  return permission;
@@ -410,6 +415,9 @@ class PermissionSet {
410
415
  return bit;
411
416
  }
412
417
  if (typeof permission === "string") {
418
+ const renamed = PermissionSet.#renamed[permission];
419
+ if (renamed)
420
+ return this.#resolve(renamed);
413
421
  if (permission in Permission)
414
422
  return Permission[permission];
415
423
  if (permission in Permissions)
@@ -1627,7 +1635,7 @@ class ResourceManager extends Manager {
1627
1635
  // packages/rest/package.json
1628
1636
  var package_default = {
1629
1637
  name: "@lunibee/rest",
1630
- version: "0.2.0",
1638
+ version: "0.2.1",
1631
1639
  type: "module",
1632
1640
  module: "./src/index.ts",
1633
1641
  types: "./src/index.ts",
@@ -2612,6 +2620,11 @@ class Channel extends BaseStructure {
2612
2620
  editTopic(topic) {
2613
2621
  return this.edit({ topic });
2614
2622
  }
2623
+ editPermissionOverwrite(targetId, changes, options) {
2624
+ if (!this.#context?.editPermissionOverwrite)
2625
+ throw new Error("This channel is not attached to a client.");
2626
+ return this.#context.editPermissionOverwrite(this.id, targetId, changes, options);
2627
+ }
2615
2628
  editParent(parentId) {
2616
2629
  return this.edit({ parent_id: parentId });
2617
2630
  }
@@ -2746,6 +2759,7 @@ class Guild extends BaseStructure {
2746
2759
  return this.name;
2747
2760
  }
2748
2761
  }
2762
+
2749
2763
  // packages/structures/src/resources.ts
2750
2764
  function toDateOrNull(value) {
2751
2765
  if (!value)
@@ -2761,13 +2775,15 @@ class GuildMember {
2761
2775
  roleIds;
2762
2776
  pending;
2763
2777
  joinedAt;
2764
- permissions;
2765
2778
  avatarHash;
2766
2779
  premiumSince;
2767
2780
  timedOutUntil;
2768
2781
  flags;
2769
- constructor(data) {
2782
+ #suppliedPermissions;
2783
+ #context;
2784
+ constructor(data, context) {
2770
2785
  this.user = new User(data.user);
2786
+ this.#context = context;
2771
2787
  if (!/^\d{1,20}$/.test(data.guild_id))
2772
2788
  throw new TypeError("Member guild_id must be a valid snowflake.");
2773
2789
  this.guildId = data.guild_id;
@@ -2777,12 +2793,53 @@ class GuildMember {
2777
2793
  this.joinedAt = data.joined_at ? new Date(data.joined_at) : undefined;
2778
2794
  if (this.joinedAt?.toString() === "Invalid Date")
2779
2795
  throw new RangeError("Member joined_at must be a valid date.");
2780
- this.permissions = new PermissionsBitField(data.permissions ?? 0n);
2796
+ if (data.permissions !== undefined)
2797
+ this.#suppliedPermissions = new PermissionsBitField(data.permissions);
2781
2798
  this.avatarHash = data.avatar ?? null;
2782
2799
  this.premiumSince = toDateOrNull(data.premium_since);
2783
2800
  this.timedOutUntil = toDateOrNull(data.communication_disabled_until);
2784
2801
  this.flags = data.flags ?? 0;
2785
2802
  }
2803
+ get permissions() {
2804
+ if (this.#suppliedPermissions)
2805
+ return this.#suppliedPermissions;
2806
+ return new PermissionsBitField(this.#context?.memberPermissions?.(this.guildId, this.user.id, this.roleIds) ?? 0n);
2807
+ }
2808
+ permissionsIn(channelId) {
2809
+ const computed = this.#context?.memberPermissions?.(this.guildId, this.user.id, this.roleIds, channelId);
2810
+ return computed ? new PermissionsBitField(computed) : null;
2811
+ }
2812
+ #action(name) {
2813
+ const action = this.#context?.[name];
2814
+ if (!action)
2815
+ throw new Error("This member is not attached to a client.");
2816
+ return action;
2817
+ }
2818
+ kick(reason) {
2819
+ return this.#action("kickMember")(this.guildId, this.user.id, reason);
2820
+ }
2821
+ ban(options = {}) {
2822
+ return this.#action("banMember")(this.guildId, this.user.id, options);
2823
+ }
2824
+ edit(options, reason) {
2825
+ return this.#action("editMember")(this.guildId, this.user.id, options, reason);
2826
+ }
2827
+ timeout(milliseconds, reason) {
2828
+ if (milliseconds !== null && !(milliseconds > 0))
2829
+ throw new RangeError("Timeout length must be a positive number of milliseconds.");
2830
+ return this.edit({
2831
+ communication_disabled_until: milliseconds === null ? null : new Date(Date.now() + milliseconds).toISOString()
2832
+ }, reason);
2833
+ }
2834
+ setNickname(nickname, reason) {
2835
+ return this.edit({ nick: nickname }, reason);
2836
+ }
2837
+ addRole(roleId, reason) {
2838
+ return this.#action("addMemberRole")(this.guildId, this.user.id, roleId, reason);
2839
+ }
2840
+ removeRole(roleId, reason) {
2841
+ return this.#action("removeMemberRole")(this.guildId, this.user.id, roleId, reason);
2842
+ }
2786
2843
  get displayName() {
2787
2844
  return this.nickname ?? this.user.displayName;
2788
2845
  }
@@ -3316,6 +3373,17 @@ class CommandOptions {
3316
3373
  throw new TypeError(`Resolved mentionable for option "${name}" is missing.`);
3317
3374
  return resolved;
3318
3375
  }
3376
+ getMentionableType(name) {
3377
+ const opt = this.#get(name);
3378
+ if (!opt || opt.type !== OptionType.Mentionable)
3379
+ return null;
3380
+ const id = String(opt.value);
3381
+ if (this.#resolved?.users?.[id])
3382
+ return "user";
3383
+ if (this.#resolved?.roles?.[id])
3384
+ return "role";
3385
+ return null;
3386
+ }
3319
3387
  getAttachment(name, required = false) {
3320
3388
  const opt = this.#get(name);
3321
3389
  if (!opt || opt.type !== OptionType.Attachment) {
@@ -3403,6 +3471,20 @@ class Interaction {
3403
3471
  isChatInputCommand() {
3404
3472
  return this.type === InteractionType.ApplicationCommand;
3405
3473
  }
3474
+ awaitModalSubmit(options) {
3475
+ const collect = this.#client.resourceContext?.collectInteractions;
3476
+ if (!collect)
3477
+ return Promise.reject(new Error("This interaction is not attached to a client."));
3478
+ if (!(options.time > 0))
3479
+ return Promise.reject(new RangeError("awaitModalSubmit needs a positive time."));
3480
+ const userId = this.user?.id;
3481
+ const collector = collect({
3482
+ time: options.time,
3483
+ max: 1,
3484
+ filter: async (interaction) => interaction.isModalSubmit() && interaction.user?.id === userId && (options.customId === undefined || interaction.customId === options.customId) && (options.filter ? await options.filter(interaction) : true)
3485
+ });
3486
+ return collector.next();
3487
+ }
3406
3488
  isMessageComponent() {
3407
3489
  return this.type === InteractionType.MessageComponent;
3408
3490
  }
@@ -3462,7 +3544,7 @@ class Interaction {
3462
3544
  return new GuildMember({
3463
3545
  ...raw,
3464
3546
  guild_id: this.guildId
3465
- });
3547
+ }, this.#client.resourceContext);
3466
3548
  }
3467
3549
  get createdTimestamp() {
3468
3550
  return Number((BigInt(this.id) >> 22n) + DISCORD_EPOCH);
@@ -3498,7 +3580,8 @@ class Interaction {
3498
3580
  async reply(options) {
3499
3581
  return this.acknowledge(InteractionResponse.message(toMessageData(options)), "replied");
3500
3582
  }
3501
- async deferReply(ephemeral = false) {
3583
+ async deferReply(options = false) {
3584
+ const ephemeral = typeof options === "boolean" ? options : options.ephemeral === true;
3502
3585
  await this.acknowledge(InteractionResponse.defer(ephemeral), "deferred");
3503
3586
  }
3504
3587
  editReply(options) {
@@ -3516,7 +3599,8 @@ class Interaction {
3516
3599
  return this.acknowledge(new InteractionResponse(InteractionResponseType.MessageUpdate, toMessageData(options)), "replied");
3517
3600
  }
3518
3601
  async showModal(modal) {
3519
- return this.acknowledge(new InteractionResponse(InteractionResponseType.Modal, modal), "replied");
3602
+ const data = "toJSON" in modal && typeof modal.toJSON === "function" ? modal.toJSON() : modal;
3603
+ return this.acknowledge(new InteractionResponse(InteractionResponseType.Modal, data), "replied");
3520
3604
  }
3521
3605
  }
3522
3606
 
@@ -3537,6 +3621,9 @@ class ComponentInteraction extends Interaction {
3537
3621
  get customId() {
3538
3622
  return this.data?.data?.custom_id ?? "";
3539
3623
  }
3624
+ get messageId() {
3625
+ return this.data?.message?.id;
3626
+ }
3540
3627
  get componentType() {
3541
3628
  return this.data?.data?.component_type ?? 0;
3542
3629
  }
@@ -3787,6 +3874,7 @@ class AuditLog {
3787
3874
  }
3788
3875
 
3789
3876
  // packages/structures/src/index.ts
3877
+ var COMPONENT_COLLECTOR_DEFAULT_TIME = 15 * 60000;
3790
3878
  var NON_SYSTEM_MESSAGE_TYPES = new Set([0, 19, 20, 23]);
3791
3879
 
3792
3880
  class Message extends BaseStructure {
@@ -3807,6 +3895,7 @@ class Message extends BaseStructure {
3807
3895
  reference;
3808
3896
  components;
3809
3897
  referencedMessage;
3898
+ member;
3810
3899
  #context;
3811
3900
  constructor(data, context) {
3812
3901
  super(data.id);
@@ -3829,6 +3918,11 @@ class Message extends BaseStructure {
3829
3918
  this.reference = data.message_reference;
3830
3919
  this.referencedMessage = data.referenced_message ? new Message(data.referenced_message, context) : data.referenced_message === null ? null : undefined;
3831
3920
  this.#context = context;
3921
+ this.member = data.member && data.guild_id ? new GuildMember({
3922
+ ...data.member,
3923
+ user: data.member.user ?? data.author,
3924
+ guild_id: data.guild_id
3925
+ }, context) : null;
3832
3926
  this.channel = new Channel({ id: data.channel_id, type: 0, guild_id: data.guild_id }, context);
3833
3927
  }
3834
3928
  get embedsSuppressed() {
@@ -3869,6 +3963,20 @@ class Message extends BaseStructure {
3869
3963
  throw new Error("This message is not attached to a client.");
3870
3964
  return this.#context.crosspostMessage(this.channelId, this.id);
3871
3965
  }
3966
+ createComponentCollector(options = {}) {
3967
+ const collect = this.#context?.collectInteractions;
3968
+ if (!collect)
3969
+ throw new Error("This message is not attached to a client.");
3970
+ const { componentType, filter, ...rest } = options;
3971
+ return collect({
3972
+ ...rest,
3973
+ time: rest.time ?? (rest.idle ? undefined : COMPONENT_COLLECTOR_DEFAULT_TIME),
3974
+ filter: async (interaction) => interaction.isMessageComponent() && interaction.messageId === this.id && (componentType === undefined || interaction.componentType === componentType) && (filter ? await filter(interaction) : true)
3975
+ });
3976
+ }
3977
+ awaitComponent(options = {}) {
3978
+ return this.createComponentCollector({ ...options, max: 1 }).next();
3979
+ }
3872
3980
  react(emoji) {
3873
3981
  if (!this.#context?.addReaction)
3874
3982
  throw new Error("This message is not attached to a client.");
@@ -3942,6 +4050,20 @@ class Message extends BaseStructure {
3942
4050
  }
3943
4051
 
3944
4052
  // packages/managers/src/message.ts
4053
+ function toRequest(options) {
4054
+ const { files, ...body } = options;
4055
+ if (!files?.length)
4056
+ return body;
4057
+ return {
4058
+ body,
4059
+ files: files.map((file) => ({
4060
+ name: file.name,
4061
+ data: typeof file.data === "string" ? new TextEncoder().encode(file.data) : file.data,
4062
+ contentType: file.contentType
4063
+ }))
4064
+ };
4065
+ }
4066
+
3945
4067
  class MessageManager {
3946
4068
  cache;
3947
4069
  #caching;
@@ -3964,7 +4086,7 @@ class MessageManager {
3964
4086
  return this.cache.get(messageId) ?? this.fetch(messageId);
3965
4087
  }
3966
4088
  async send(options) {
3967
- const data = await this.#rest.post(Routes.channelMessages(this.#channelId), options);
4089
+ const data = await this.#rest.post(Routes.channelMessages(this.#channelId), toRequest(options));
3968
4090
  return this.upsert(data);
3969
4091
  }
3970
4092
  async fetch(messageId) {
@@ -4245,14 +4367,20 @@ class MonetizationManager extends Manager {
4245
4367
  // packages/managers/src/member.ts
4246
4368
  class GuildMemberManager extends ResourceManager {
4247
4369
  #rest;
4370
+ #context;
4248
4371
  guildId;
4249
- constructor(guildId, rest) {
4250
- super((id) => rest.get(Routes.guildMember(guildId, id)).then((data) => new GuildMember({ ...data, guild_id: guildId })), (member) => member.user.id);
4372
+ constructor(guildId, rest, context = () => {
4373
+ return;
4374
+ }) {
4375
+ super((id) => rest.get(Routes.guildMember(guildId, id)).then((data) => new GuildMember({ ...data, guild_id: guildId }, context())), (member) => member.user.id);
4251
4376
  this.guildId = guildId;
4252
4377
  this.#rest = rest;
4378
+ this.#context = context;
4253
4379
  }
4254
- async kick(userId) {
4255
- await this.#rest.delete(Routes.guildMember(this.guildId, userId));
4380
+ async kick(userId, reason) {
4381
+ await this.#rest.delete(Routes.guildMember(this.guildId, userId), {
4382
+ reason
4383
+ });
4256
4384
  this.delete(userId);
4257
4385
  }
4258
4386
  async ban(userId, options = {}) {
@@ -4262,21 +4390,21 @@ class GuildMemberManager extends ResourceManager {
4262
4390
  async unban(userId) {
4263
4391
  await this.#rest.delete(Routes.guildBan(this.guildId, userId));
4264
4392
  }
4265
- async edit(userId, options) {
4266
- const data = await this.#rest.patch(Routes.guildMember(this.guildId, userId), options);
4267
- const member = new GuildMember({ ...data, guild_id: this.guildId });
4393
+ async edit(userId, options, reason) {
4394
+ const data = await this.#rest.patch(Routes.guildMember(this.guildId, userId), options, { reason });
4395
+ const member = new GuildMember({ ...data, guild_id: this.guildId }, this.#context());
4268
4396
  this.set(member.user.id, member);
4269
4397
  return member;
4270
4398
  }
4271
- async addRole(userId, roleId) {
4272
- await this.#rest.put(Routes.guildMemberRole(this.guildId, userId, roleId));
4399
+ async addRole(userId, roleId, reason) {
4400
+ await this.#rest.put(Routes.guildMemberRole(this.guildId, userId, roleId), undefined, { reason });
4273
4401
  }
4274
- async removeRole(userId, roleId) {
4275
- await this.#rest.delete(Routes.guildMemberRole(this.guildId, userId, roleId));
4402
+ async removeRole(userId, roleId, reason) {
4403
+ await this.#rest.delete(Routes.guildMemberRole(this.guildId, userId, roleId), { reason });
4276
4404
  }
4277
- async timeout(userId, milliseconds) {
4405
+ async timeout(userId, milliseconds, reason) {
4278
4406
  const timeoutDate = milliseconds === null ? null : new Date(Date.now() + milliseconds).toISOString();
4279
- return this.edit(userId, { communication_disabled_until: timeoutDate });
4407
+ return this.edit(userId, { communication_disabled_until: timeoutDate }, reason);
4280
4408
  }
4281
4409
  }
4282
4410
 
@@ -4447,10 +4575,25 @@ class StageInstanceManager extends Manager {
4447
4575
 
4448
4576
  class PermissionOverwriteManager {
4449
4577
  #rest;
4578
+ #current;
4450
4579
  channelId;
4451
- constructor(rest, channelId) {
4580
+ constructor(rest, channelId, current = () => {
4581
+ return;
4582
+ }) {
4452
4583
  this.#rest = rest;
4453
4584
  this.channelId = channelId;
4585
+ this.#current = current;
4586
+ }
4587
+ async update(overwriteId, changes, options = {}) {
4588
+ const overwrites = this.#current() ?? (await this.#rest.get(Routes.channel(this.channelId))).permission_overwrites ?? [];
4589
+ const existing = overwrites.find((entry) => entry.id === overwriteId);
4590
+ const type = existing?.type ?? options.type;
4591
+ if (type !== 0 && type !== 1)
4592
+ throw new TypeError("A new permission overwrite needs a type: 0 for a role, 1 for a member.");
4593
+ const touched = (changes.allow ?? 0n) | (changes.deny ?? 0n) | (changes.inherit ?? 0n);
4594
+ const allow = BigInt(existing?.allow ?? 0) & ~touched | (changes.allow ?? 0n);
4595
+ const deny = BigInt(existing?.deny ?? 0) & ~touched | (changes.deny ?? 0n);
4596
+ await this.edit(overwriteId, { type, allow, deny }, options.reason);
4454
4597
  }
4455
4598
  async edit(overwriteId, options, reason) {
4456
4599
  await this.#rest.put(Routes.channelPermission(this.channelId, overwriteId), {
@@ -4482,6 +4625,10 @@ class GuildManager extends ResourceManager {
4482
4625
  #voiceStates = new Map;
4483
4626
  #autoModerationRules = new Map;
4484
4627
  #invites = new Map;
4628
+ #context;
4629
+ attachContext(context) {
4630
+ this.#context = context;
4631
+ }
4485
4632
  #perGuild(map, guildId, create) {
4486
4633
  let manager = map.get(guildId);
4487
4634
  if (!manager)
@@ -4507,7 +4654,7 @@ class GuildManager extends ResourceManager {
4507
4654
  members(guildId) {
4508
4655
  let manager = this.#members.get(guildId);
4509
4656
  if (!manager)
4510
- this.#members.set(guildId, manager = new GuildMemberManager(guildId, this.#rest));
4657
+ this.#members.set(guildId, manager = new GuildMemberManager(guildId, this.#rest, () => this.#context));
4511
4658
  return manager;
4512
4659
  }
4513
4660
  roles(guildId) {
@@ -4763,7 +4910,7 @@ class ChannelManager extends Manager {
4763
4910
  return manager;
4764
4911
  }
4765
4912
  permissionOverwrites(channelId) {
4766
- return new PermissionOverwriteManager(this.#rest, channelId);
4913
+ return new PermissionOverwriteManager(this.#rest, channelId, () => this.get(channelId)?.permissionOverwrites);
4767
4914
  }
4768
4915
  threads(channelId) {
4769
4916
  return new ThreadManager(this.#rest, this.#context, channelId);
@@ -4863,7 +5010,7 @@ class ChannelManager extends Manager {
4863
5010
  return this.messages(data.channel_id).upsert(data);
4864
5011
  }
4865
5012
  async editMessage(channelId, messageId, options) {
4866
- return this.messages(channelId).upsert(await this.#rest.patch(Routes.message(channelId, messageId), options));
5013
+ return this.messages(channelId).upsert(await this.#rest.patch(Routes.message(channelId, messageId), toRequest(options)));
4867
5014
  }
4868
5015
  async deleteMessage(channelId, messageId) {
4869
5016
  await this.#rest.delete(Routes.message(channelId, messageId));
@@ -6197,8 +6344,32 @@ class Client extends EventEmitter2 {
6197
6344
  removeReaction: (channelId, messageId, emoji, userId) => this.channels.removeReaction(channelId, messageId, emoji, userId),
6198
6345
  removeAllReactions: (channelId, messageId) => this.channels.removeAllReactions(channelId, messageId),
6199
6346
  pinMessage: (channelId, messageId) => this.channels.pinMessage(channelId, messageId),
6200
- unpinMessage: (channelId, messageId) => this.channels.unpinMessage(channelId, messageId)
6347
+ unpinMessage: (channelId, messageId) => this.channels.unpinMessage(channelId, messageId),
6348
+ collectInteractions: (options) => this.createCollector("interactionCreate" /* InteractionCreate */, options),
6349
+ memberPermissions: (guildId, memberId, roleIds, channelId) => this.#memberPermissions(guildId, memberId, roleIds, channelId),
6350
+ kickMember: (guildId, userId, reason) => this.guilds.members(guildId).kick(userId, reason),
6351
+ banMember: (guildId, userId, options) => this.guilds.members(guildId).ban(userId, options),
6352
+ editMember: (guildId, userId, options, reason) => this.guilds.members(guildId).edit(userId, options, reason),
6353
+ addMemberRole: (guildId, userId, roleId, reason) => this.guilds.members(guildId).addRole(userId, roleId, reason),
6354
+ removeMemberRole: (guildId, userId, roleId, reason) => this.guilds.members(guildId).removeRole(userId, roleId, reason),
6355
+ editPermissionOverwrite: async (channelId, targetId, changes, options) => {
6356
+ const bits = { allow: 0n, deny: 0n, inherit: 0n };
6357
+ for (const [name, value] of Object.entries(changes)) {
6358
+ if (!/^[A-Za-z]+$/.test(name))
6359
+ throw new TypeError(`Unknown permission: ${name}`);
6360
+ let bit;
6361
+ try {
6362
+ bit = new PermissionSet(name).bitfield;
6363
+ } catch {
6364
+ throw new TypeError(`Unknown permission: ${name}`);
6365
+ }
6366
+ const key = value === true ? "allow" : value === false ? "deny" : "inherit";
6367
+ bits[key] |= bit;
6368
+ }
6369
+ return this.channels.permissionOverwrites(channelId).update(targetId, bits, options);
6370
+ }
6201
6371
  };
6372
+ this.guilds.attachContext(this.#resourceContext);
6202
6373
  this.#gateway = new Gateway({
6203
6374
  token: options.token,
6204
6375
  intents: options.intents,
@@ -6230,8 +6401,14 @@ class Client extends EventEmitter2 {
6230
6401
  this.emit("close" /* Close */, data);
6231
6402
  });
6232
6403
  this.#gateway.on("MESSAGE_CREATE", (data) => {
6233
- const message = new Message(data, this.#resourceContext);
6404
+ const payload = data;
6405
+ const message = new Message(payload, this.#resourceContext);
6234
6406
  this.#observeMessage(message);
6407
+ if (payload.member && payload.guild_id && this.guilds.has(payload.guild_id))
6408
+ this.#upsertMember(payload.guild_id, {
6409
+ ...payload.member,
6410
+ user: payload.member.user ?? payload.author
6411
+ });
6235
6412
  const cached = this.options.messageCache ? this.channels.messages(message.channelId).upsert(data) : message;
6236
6413
  this.emit("messageCreate" /* MessageCreate */, cached);
6237
6414
  });
@@ -6536,7 +6713,7 @@ class Client extends EventEmitter2 {
6536
6713
  this.#merge(this.users, message.author.id, message.author);
6537
6714
  }
6538
6715
  #upsertMember(guildId, data) {
6539
- const member = new GuildMember({ ...data, guild_id: guildId });
6716
+ const member = new GuildMember({ ...data, guild_id: guildId }, this.#resourceContext);
6540
6717
  if (this.#cache.users)
6541
6718
  this.#merge(this.users, member.user.id, member.user);
6542
6719
  if (!this.#cache.members)
@@ -6579,6 +6756,29 @@ class Client extends EventEmitter2 {
6579
6756
  collector.onDispose(() => this.off(event, listener));
6580
6757
  return collector;
6581
6758
  }
6759
+ get resourceContext() {
6760
+ return this.#resourceContext;
6761
+ }
6762
+ #memberPermissions(guildId, memberId, roleIds, channelId) {
6763
+ const guild = this.guilds.get(guildId);
6764
+ if (!guild)
6765
+ return null;
6766
+ let channel = channelId ? this.channels.get(channelId) : undefined;
6767
+ if (channelId) {
6768
+ if (channel?.isThread())
6769
+ channel = channel.parentId ? this.channels.get(channel.parentId) : undefined;
6770
+ if (!channel || channel.guildId !== guildId)
6771
+ return null;
6772
+ }
6773
+ return computePermissions({
6774
+ guildId,
6775
+ ownerId: guild.ownerId,
6776
+ memberId,
6777
+ memberRoleIds: [...roleIds],
6778
+ roles: this.guilds.roles(guildId).values(),
6779
+ overwrites: channel?.permissionOverwrites
6780
+ });
6781
+ }
6582
6782
  permissionsFor(memberId, guildOrChannelId) {
6583
6783
  let channel = this.channels.get(guildOrChannelId);
6584
6784
  if (channel?.isThread()) {
@@ -6622,12 +6822,21 @@ class Client extends EventEmitter2 {
6622
6822
  this.#gateway.close();
6623
6823
  }
6624
6824
  postInteractionResponse(id, token, response) {
6625
- return this.rest.post(Routes.interactionCallback(id, token), response.toJSON());
6825
+ const json = response.toJSON();
6826
+ const upload = json.data ? toRequest(json.data) : undefined;
6827
+ if (upload && typeof upload === "object" && "files" in upload) {
6828
+ const { body, files } = upload;
6829
+ return this.rest.post(Routes.interactionCallback(id, token), {
6830
+ body: { ...json, data: body },
6831
+ files
6832
+ });
6833
+ }
6834
+ return this.rest.post(Routes.interactionCallback(id, token), json);
6626
6835
  }
6627
6836
  editInteractionReply(token, data) {
6628
6837
  if (!this.user)
6629
6838
  return Promise.reject(new Error("Client is unauthenticated."));
6630
- return this.rest.patch(Routes.interactionOriginalResponse(this.user.id, token), data);
6839
+ return this.rest.patch(Routes.interactionOriginalResponse(this.user.id, token), toRequest(data));
6631
6840
  }
6632
6841
  deleteInteractionReply(token) {
6633
6842
  if (!this.user)
@@ -6637,7 +6846,7 @@ class Client extends EventEmitter2 {
6637
6846
  followUpInteraction(token, data) {
6638
6847
  if (!this.user)
6639
6848
  return Promise.reject(new Error("Client is unauthenticated."));
6640
- return this.rest.post(`/webhooks/${this.user.id}/${token}`, data);
6849
+ return this.rest.post(`/webhooks/${this.user.id}/${token}`, toRequest(data));
6641
6850
  }
6642
6851
  interactionWebhookMessage(method, applicationId, token, messageId, data) {
6643
6852
  const path = messageId === "@original" ? Routes.interactionOriginalResponse(applicationId, token) : Routes.webhookMessage(applicationId, token, messageId);
@@ -6805,7 +7014,7 @@ class HandlerRegistry {
6805
7014
  // packages/sharding/package.json
6806
7015
  var package_default2 = {
6807
7016
  name: "@lunibee/sharding",
6808
- version: "0.2.0",
7017
+ version: "0.2.1",
6809
7018
  type: "module",
6810
7019
  module: "./src/index.ts",
6811
7020
  types: "./src/index.ts",
@@ -7339,6 +7548,187 @@ class ShardManager {
7339
7548
  });
7340
7549
  }
7341
7550
  }
7551
+ // packages/utils/src/args.ts
7552
+ var SNOWFLAKE = /^\d{16,22}$/;
7553
+ var TRUE_WORDS = new Set([
7554
+ "true",
7555
+ "yes",
7556
+ "y",
7557
+ "on",
7558
+ "1",
7559
+ "enable",
7560
+ "enabled"
7561
+ ]);
7562
+ var FALSE_WORDS = new Set([
7563
+ "false",
7564
+ "no",
7565
+ "n",
7566
+ "off",
7567
+ "0",
7568
+ "disable",
7569
+ "disabled"
7570
+ ]);
7571
+ function tokenizeArgs(input) {
7572
+ const args = [];
7573
+ let current = "";
7574
+ let quote = null;
7575
+ let started = false;
7576
+ for (let index = 0;index < input.length; index++) {
7577
+ const character = input[index];
7578
+ if (character === "\\" && index + 1 < input.length) {
7579
+ current += input[++index];
7580
+ started = true;
7581
+ } else if (quote) {
7582
+ if (character === quote)
7583
+ quote = null;
7584
+ else
7585
+ current += character;
7586
+ } else if (character === '"' || character === "'") {
7587
+ if (started)
7588
+ current += character;
7589
+ else {
7590
+ quote = character;
7591
+ started = true;
7592
+ }
7593
+ } else if (/\s/.test(character)) {
7594
+ if (started)
7595
+ args.push(current);
7596
+ current = "";
7597
+ started = false;
7598
+ } else {
7599
+ current += character;
7600
+ started = true;
7601
+ }
7602
+ }
7603
+ if (started)
7604
+ args.push(current);
7605
+ return args;
7606
+ }
7607
+ function parseUserMention(value) {
7608
+ const id = /^<@!?(\d{16,22})>$/.exec(value)?.[1] ?? value;
7609
+ return SNOWFLAKE.test(id) ? id : null;
7610
+ }
7611
+ function parseRoleMention(value) {
7612
+ const id = /^<@&(\d{16,22})>$/.exec(value)?.[1] ?? value;
7613
+ return SNOWFLAKE.test(id) ? id : null;
7614
+ }
7615
+ function parseChannelMention(value) {
7616
+ const id = /^<#(\d{16,22})>$/.exec(value)?.[1] ?? value;
7617
+ return SNOWFLAKE.test(id) ? id : null;
7618
+ }
7619
+ function parseMentionable(value) {
7620
+ const role = /^<@&(\d{16,22})>$/.exec(value)?.[1];
7621
+ if (role)
7622
+ return { id: role, type: "role" };
7623
+ const user = parseUserMention(value);
7624
+ return user ? { id: user, type: "user" } : null;
7625
+ }
7626
+ function readOne(spec, raw) {
7627
+ switch (spec.type) {
7628
+ case "string":
7629
+ case "rest":
7630
+ if (spec.maxLength !== undefined && raw.length > spec.maxLength)
7631
+ return {
7632
+ error: `must be at most ${spec.maxLength} characters`
7633
+ };
7634
+ if (spec.choices && !spec.choices.some((choice) => String(choice).toLowerCase() === raw.toLowerCase()))
7635
+ return { error: `must be one of: ${spec.choices.join(", ")}` };
7636
+ return { value: raw };
7637
+ case "integer":
7638
+ case "number": {
7639
+ const value = Number(raw);
7640
+ if (!Number.isFinite(value) || raw.trim() === "")
7641
+ return { error: "must be a number" };
7642
+ if (spec.type === "integer" && !Number.isSafeInteger(value))
7643
+ return { error: "must be a whole number" };
7644
+ if (spec.min !== undefined && value < spec.min)
7645
+ return { error: `must be at least ${spec.min}` };
7646
+ if (spec.max !== undefined && value > spec.max)
7647
+ return { error: `must be at most ${spec.max}` };
7648
+ if (spec.choices && !spec.choices.includes(value))
7649
+ return { error: `must be one of: ${spec.choices.join(", ")}` };
7650
+ return { value };
7651
+ }
7652
+ case "boolean": {
7653
+ const word = raw.toLowerCase();
7654
+ if (TRUE_WORDS.has(word))
7655
+ return { value: true };
7656
+ if (FALSE_WORDS.has(word))
7657
+ return { value: false };
7658
+ return { error: "must be yes or no" };
7659
+ }
7660
+ case "user": {
7661
+ const id = parseUserMention(raw);
7662
+ return id ? { value: id } : { error: "must be a user mention or ID" };
7663
+ }
7664
+ case "role": {
7665
+ const id = parseRoleMention(raw);
7666
+ return id ? { value: id } : { error: "must be a role mention or ID" };
7667
+ }
7668
+ case "channel": {
7669
+ const id = parseChannelMention(raw);
7670
+ return id ? { value: id } : { error: "must be a channel mention or ID" };
7671
+ }
7672
+ case "mentionable": {
7673
+ const value = parseMentionable(raw);
7674
+ return value ? { value } : { error: "must be a user or role mention" };
7675
+ }
7676
+ }
7677
+ }
7678
+ function parsePrefixArgs(input, specs) {
7679
+ const args = typeof input === "string" ? tokenizeArgs(input) : [...input];
7680
+ const values = {};
7681
+ let position = 0;
7682
+ for (const [index, spec] of specs.entries()) {
7683
+ if (spec.type === "rest" && index !== specs.length - 1)
7684
+ throw new TypeError(`The rest argument "${spec.name}" must be the last one.`);
7685
+ const raw = spec.type === "rest" ? args.slice(position).join(" ") : args[position];
7686
+ if (raw === undefined || raw === "") {
7687
+ if (spec.required)
7688
+ return { ok: false, arg: spec.name, error: "is required" };
7689
+ values[spec.name] = undefined;
7690
+ continue;
7691
+ }
7692
+ const read = readOne(spec, raw);
7693
+ if ("error" in read)
7694
+ return { ok: false, arg: spec.name, error: read.error };
7695
+ values[spec.name] = read.value;
7696
+ position += spec.type === "rest" ? args.length : 1;
7697
+ }
7698
+ return { ok: true, values };
7699
+ }
7700
+ var OPTION_TYPES = {
7701
+ 3: "string",
7702
+ 4: "integer",
7703
+ 5: "boolean",
7704
+ 6: "user",
7705
+ 7: "channel",
7706
+ 8: "role",
7707
+ 9: "mentionable",
7708
+ 10: "number"
7709
+ };
7710
+ function argsFromCommandOptions(options, restLast = false) {
7711
+ const specs = [];
7712
+ for (const option of options) {
7713
+ const type = OPTION_TYPES[option.type];
7714
+ if (!type)
7715
+ continue;
7716
+ specs.push({
7717
+ name: option.name,
7718
+ type,
7719
+ required: option.required,
7720
+ min: option.min_value,
7721
+ max: option.max_value,
7722
+ maxLength: option.max_length,
7723
+ choices: option.choices?.map((choice) => choice.value)
7724
+ });
7725
+ }
7726
+ const last = specs[specs.length - 1];
7727
+ if (restLast && last?.type === "string")
7728
+ last.type = "rest";
7729
+ return specs;
7730
+ }
7731
+
7342
7732
  // packages/utils/src/index.ts
7343
7733
  function sleep4(ms) {
7344
7734
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -7761,15 +8151,24 @@ function entersState(target, status, timeoutMs) {
7761
8151
  class EmbedBuilder {
7762
8152
  #data = {};
7763
8153
  setTitle(value) {
7764
- this.#data.title = validate(value, 256, "Embed title");
8154
+ if (value === null)
8155
+ delete this.#data.title;
8156
+ else
8157
+ this.#data.title = validate(value, 256, "Embed title");
7765
8158
  return this;
7766
8159
  }
7767
8160
  setDescription(value) {
7768
- this.#data.description = validate(value, 4096, "Embed description");
8161
+ if (value === null)
8162
+ delete this.#data.description;
8163
+ else
8164
+ this.#data.description = validate(value, 4096, "Embed description");
7769
8165
  return this;
7770
8166
  }
7771
8167
  setURL(value) {
7772
- this.#data.url = url(value, "Embed URL");
8168
+ if (value === null)
8169
+ delete this.#data.url;
8170
+ else
8171
+ this.#data.url = url(value, "Embed URL");
7773
8172
  return this;
7774
8173
  }
7775
8174
  setColor(value) {
@@ -7801,11 +8200,19 @@ class EmbedBuilder {
7801
8200
  return this;
7802
8201
  }
7803
8202
  setThumbnail(value) {
8203
+ if (value === null) {
8204
+ delete this.#data.thumbnail;
8205
+ return this;
8206
+ }
7804
8207
  const valueURL = typeof value === "string" ? value : value.url;
7805
8208
  this.#data.thumbnail = { url: url(valueURL, "Thumbnail URL") };
7806
8209
  return this;
7807
8210
  }
7808
8211
  setImage(value) {
8212
+ if (value === null) {
8213
+ delete this.#data.image;
8214
+ return this;
8215
+ }
7809
8216
  const valueURL = typeof value === "string" ? value : value.url;
7810
8217
  this.#data.image = { url: url(valueURL, "Image URL") };
7811
8218
  return this;
@@ -8132,6 +8539,9 @@ class ModalBuilder {
8132
8539
  this.#components.push(...components);
8133
8540
  return this;
8134
8541
  }
8542
+ addTextInputs(...inputs) {
8543
+ return this.addComponents(...inputs.map((input) => new ActionRowBuilder().addComponents(input)));
8544
+ }
8135
8545
  toJSON() {
8136
8546
  if (!this.#custom_id || !this.#title)
8137
8547
  throw new TypeError("Modals require a custom ID and a title.");
@@ -8139,8 +8549,8 @@ class ModalBuilder {
8139
8549
  throw new RangeError("Modals require at least one component.");
8140
8550
  return {
8141
8551
  type: 9,
8142
- ...this.#custom_id ? { custom_id: this.#custom_id } : {},
8143
- ...this.#title ? { title: this.#title } : {},
8552
+ custom_id: this.#custom_id,
8553
+ title: this.#title,
8144
8554
  components: this.#components.map((component) => component.toJSON())
8145
8555
  };
8146
8556
  }
@@ -8428,6 +8838,17 @@ function assertSelect(data) {
8428
8838
  if ((data.min_values ?? 1) > (data.max_values ?? 1))
8429
8839
  throw new RangeError("min_values cannot exceed max_values.");
8430
8840
  }
8841
+ var IS_COMPONENTS_V2 = 1 << 15;
8842
+ function componentsV2Message(components, options) {
8843
+ const list = Array.isArray(components) ? components : [components];
8844
+ if (!list.length)
8845
+ throw new TypeError("A Components V2 message needs at least one component.");
8846
+ return {
8847
+ ...options ?? {},
8848
+ components: list.map((component) => component.toJSON()),
8849
+ flags: (options?.flags ?? 0) | IS_COMPONENTS_V2
8850
+ };
8851
+ }
8431
8852
  // packages/builders/src/commands.ts
8432
8853
  var ApplicationCommandOptionType2 = {
8433
8854
  Subcommand: 1,
@@ -9039,6 +9460,7 @@ export {
9039
9460
  WelcomeScreenChannel,
9040
9461
  ZlibStreamDecoder,
9041
9462
  abortError,
9463
+ argsFromCommandOptions,
9042
9464
  blockQuote,
9043
9465
  bold,
9044
9466
  bulletList,
@@ -9047,6 +9469,7 @@ export {
9047
9469
  classifyFrame,
9048
9470
  classifyPayload,
9049
9471
  codeBlock,
9472
+ componentsV2Message,
9050
9473
  computePermissions,
9051
9474
  createAudioPlayer,
9052
9475
  createAudioResource,
@@ -9070,6 +9493,11 @@ export {
9070
9493
  masked,
9071
9494
  normalizeRoutePath,
9072
9495
  orderedList,
9496
+ parseChannelMention,
9497
+ parseMentionable,
9498
+ parsePrefixArgs,
9499
+ parseRoleMention,
9500
+ parseUserMention,
9073
9501
  randomInt,
9074
9502
  redactPath,
9075
9503
  resolveGatewayIntents,
@@ -9082,8 +9510,10 @@ export {
9082
9510
  strikethrough,
9083
9511
  subtext,
9084
9512
  timestamp,
9513
+ toRequest,
9514
+ tokenizeArgs,
9085
9515
  underline,
9086
9516
  userMention
9087
9517
  };
9088
9518
 
9089
- //# debugId=726AE42ABABEBEA864756E2164756E21
9519
+ //# debugId=9E598E337B852A0164756E2164756E21