@magicyan/discord 1.0.27 → 1.0.29

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/README.md CHANGED
@@ -16,121 +16,268 @@ Install with
16
16
  npm install @magicyan/discord
17
17
  ```
18
18
 
19
- Some functions summarize the way we create things with discord.js
19
+ ## Components
20
+ Easily create action rows
20
21
 
21
22
  ```ts
22
- // Create an action row of buttons with discord.js
23
- new ActionRowBuilder<ButtonBuilder>({
24
- components: [
25
- new ButtonBuilder({
26
- customId: "click-me-button",
27
- label: "Click me", style: ButtonStyle.Success,
28
- })
29
- new ButtonBuilder({
30
- customId: "dont-click-me-button",
31
- label: "Don't click me", style: ButtonStyle.Danger,
32
- })
33
- ]
34
- })
23
+ import { createRow } from "@magicyan/discord";
35
24
 
36
- // Create an action row of buttons with @magicyan/dicord
37
- createRow(
38
- new ButtonBuilder({
39
- customId: "click-me-button", label: "Click me",
40
- style: ButtonStyle.Success,
41
- })
42
- new ButtonBuilder({
43
- customId: "dont-click-me-button", label: "Don't click me",
44
- style: ButtonStyle.Danger,
45
- })
46
- )
25
+ const row = createRow(
26
+ new ButtonBuilder(/* button data... */),
27
+ new ButtonBuilder(/* button data... */),
28
+ new ButtonBuilder(/* button data... */),
29
+ );
30
+ const selectRow = createRow(
31
+ new StringSelectMenuBuilder(/* select data... */)
32
+ );
33
+ interaction.reply({ components: [row, selectRow] });
34
+ ```
35
+ Create a link button quickly
36
+ ```ts
37
+ import { createRow, createLinkButton } from "@magicyan/discord";
47
38
 
48
- // Add inputs to the modal with discord.js
49
- new ModalBuilder({
50
- customId: "my-modal",
51
- title: "Modal Title",
52
- components: [
53
- new ActionRowBuilder<TextInputBuilder>({components: [
54
- new TextInputBuilder({
55
- customId: "name-input",
56
- label: "Name",
57
- placeholder: "Enter your name",
58
- style: TextInputStyle.Short,
59
- required: true
60
- }),
61
- new TextInputBuilder({
62
- customId: "nio-modal",
63
- label: "Bio",
64
- placeholder: "Enter your bio",
65
- style: TextInputStyle.Paragraph,
66
- required: true
67
- })
68
- ]})
69
- ]
70
- })
39
+ const row = createRow(
40
+ createLinkButton({ label: "Github", url: "https://github.com/rinckodev" })
41
+ createLinkButton({ label: "Youtube", url: "https://youtube.com/@rinckodev" })
42
+ );
43
+ interaction.reply({ components: [row] });
44
+ ```
71
45
 
72
- // Add inputs to the modal with @magicyan/dicord
73
- new ModalBuilder({
74
- customId: "my-modal", title: "Modal Title",
46
+ ## Modals
47
+ A row only supports a single input, so use this function that already creates it within a row
48
+ ```ts
49
+ import { createModalInput } from "@magicyan/discord";
50
+
51
+ const modal = new ModalBuilder({
52
+ customId: "my/modal",
53
+ title: "My modal",
75
54
  components: [
76
55
  createModalInput({
77
- customId: "name-input", placeholder: "Enter your name",
78
- label: "Name", style: TextInputStyle.Short, required: true
56
+ customId: "name",
57
+ label: "Name",
58
+ style: TextInputStyle.Short,
79
59
  }),
80
60
  createModalInput({
81
- customId: "nio-modal", placeholder: "Enter your bio",
82
- label: "Bio", style: TextInputStyle.Paragraph, required: true
61
+ customId: "age",
62
+ label: "Age",
63
+ style: TextInputStyle.Short,
83
64
  }),
84
65
  ]
66
+ });
67
+ interaction.showModal(modal);
68
+ ```
69
+ Or if you prefer, you can create a record where the key is the customId
70
+ ```ts
71
+ import { createModalFields } from "@magicyan/discord";
72
+
73
+ const modal = new ModalBuilder({
74
+ customId: "my/modal",
75
+ title: "My modal",
76
+ components: createModalFields({
77
+ name: {
78
+ label: "Name",
79
+ style: TextInputStyle.Short,
80
+ },
81
+ age:{
82
+ label: "Age",
83
+ style: TextInputStyle.Short,
84
+ },
85
+ })
86
+ });
87
+ ```
88
+ Don't forget that you can define the custom id however you want
89
+ ```ts
90
+ createModalFields({
91
+ ["my-custom-input-name"]: {
92
+ label: "Name",
93
+ style: TextInputStyle.Short,
94
+ }
85
95
  })
86
96
  ```
97
+ You can transform the fields received from the interaction into a record
98
+ ```ts
99
+ import { modalFieldsToRecord } from "@magicyan/discord";
87
100
 
88
- You can create a link button quickly
101
+ function run(interaction: ModalSubmitInteraction){
102
+ const fields = modalFieldsToRecord(interaction.fields);
103
+ console.log(fields["my-custom-input-name"]);
104
+ console.log(fields.age);
105
+ }
106
+ ```
107
+ It is also possible to pass a union type in the function generic
108
+ ```ts
109
+ type FormFields = "id" | "nickname" | "bio";
110
+ function run(interaction: ModalSubmitInteraction){
111
+ const fields = modalFieldsToRecord<FormFields>(interaction.fields);
112
+ console.log(fields.id);
113
+ console.log(fields.nickname);
114
+ console.log(fields.bio);
115
+ }
116
+ ```
117
+
118
+ ## Embeds
119
+ Easily create embeds with this function
120
+ ```ts
121
+ const embed = createEmbed({
122
+ title: "Welcome",
123
+ description: "Hello world",
124
+ color: "Random"
125
+ });
126
+ ```
127
+ You can set the thumbnail and image in a simple way
128
+ ```ts
129
+ const embed = createEmbed({
130
+ // ...
131
+ thumbnail: "https://github.com/rinckodev.png",
132
+ image: guild.iconURL()
133
+ });
134
+
135
+ // Or passing an options object
136
+ const embed = createEmbed({
137
+ // ...
138
+ image: { url: "imageurl", width: 400, height: 100 }
139
+ });
140
+
141
+ //Or passing an attachment
142
+ const attachment = new AttachmentBuilder(buffer, { name: "myimage.png" });
143
+ const embed = createEmbed({
144
+ // ...
145
+ image: attachment // attachment://myimage.png
146
+ });
147
+ ```
148
+
149
+ ## Channels
150
+ You can try to get information from a channel url
151
+ ```ts
152
+ import { getChannelUrlInfo } from "@magicyan/discord";
153
+
154
+ const url = "https://discord.com/channels/537817462272557057/832829213651763210";
155
+ const { guildId, channelId } = getChannelUrlInfo(url);
156
+ console.log(guildId); // 537817462272557057
157
+ console.log(channelId); // 832829213651763210
158
+ ```
159
+ If the url does not follow the pattern of a discord channel url, the return will be an empty object
89
160
  ```ts
90
161
  const url = "https://github.com/rinckodev";
162
+ const { guildId, channelId } = getChannelUrlInfo(url);
163
+ console.log(guildId); // undefined
164
+ console.log(channelId); // undefined
165
+ ```
166
+ Find a guild channel easily with the findChannel function
167
+ ```ts
168
+ import { findChannel } from "@magicyan/discord";
91
169
 
92
- createLinkButton({ url, label: "My github" });
170
+ function run(interaction: ChatInputCommandInteraction<"cached">){
171
+ const { guild } = interaction;
172
+ const channel = findChannel(guild).byId("832829213651763210");
173
+ channel // TextChannel | undefined
174
+ }
93
175
  ```
176
+ This function searches for channels in the guild cache, by default it tries to find channels of the GuildText type, but you can change it to any type of guild channel
177
+ ```ts
178
+ const channel = findChannel(guild, ChannelType.GuildVoice).byId("832829213651763210");
179
+ // VoiceChannel | undefined
180
+ ```
181
+ You can find channels in other ways
182
+ ```ts
183
+ const general = findChannel(guild).byName("general");
184
+ const updates = findChannel(guild, ChannelType.GuildAnnouncement).byName("updates");
185
+ const lounge = findChannel(guild, ChannelType.GuildVoice).byName("Lounge 01");
186
+ const popular = findChannel(guild, ChannelType.GuildStageVoice).byFilter(f => f.members.size >= 12);
187
+ const hotforum = findChannel(guild, ChannelType.GuildForum).byFilter(f => f.threads.cache.size >= 100);
94
188
 
95
- You can create an embed author easily with a User object
189
+ general; // TextChannel | undefined
190
+ updates; // NewsChannel | undefined
191
+ lounge; // VoiceChannel | undefined
192
+ popular; // StageChannel | undefined
193
+ hotforum; // ForumChannel | undefined
194
+ ```
195
+ Find a channel in a category easily
96
196
  ```ts
97
- const { user } = interaction
197
+ const ticket = findChannel(guild)
198
+ .inCategoryName("Tickets")
199
+ .byName(`ticket-${member.id}`);
98
200
 
99
- new EmbedBuilder({
100
- author: createEmbedAuthor({ user }),
101
- description: "My embed description"
102
- })
201
+ ticket; // TextChannel | undefined
103
202
  ```
203
+ ## Roles
204
+ Find guild roles easily
205
+ ```ts
206
+ import { findRole } from "@magicyan/discord";
104
207
 
105
- Function to find a channel from the guild cache
208
+ function run(interaction: ChatInputCommandInteraction<"cached">){
209
+ const { guild } = interaction;
210
+
211
+ const memberRole = findRole(guild).byName("Member");
212
+ const adminRole = findRole(guild).byHexColor("#ff5454");
213
+ const leaderRole = findRole(guild).byId("537818031728885771");
214
+
215
+ memberRole // Role | undefined
216
+ adminRole // Role | undefined
217
+ leaderRole // Role | undefined
218
+ }
219
+ ```
220
+ ## Members
221
+ Find guild members easily
106
222
  ```ts
107
- const { guild } = interaction
223
+ import { findMember } from "@magicyan/discord";
108
224
 
109
- const channel = findChannel(guild, ChannelType.GuildVoice).byName("Lounge 01") // VoiceChannel | undefined
225
+ function run(interaction: ChatInputCommandInteraction<"cached">){
226
+ const { guild } = interaction;
227
+ const finder = findMember(guild);
228
+ const member = finder.byId("264620632644255745")
229
+ ?? finder.byUsername("rincko")
230
+ ?? finder.byGlobalName("Rincko")
231
+ ?? finder.byNickname("RinckoZ_");
232
+
233
+ member; // GuildMember | undefined
234
+ }
110
235
  ```
236
+ ## Messages
237
+ You can try to get information from a channel url
238
+ ```ts
239
+ import { getMessageUrlInfo } from "@magicyan/discord";
111
240
 
112
- Function to find a role from the guild cache
241
+ const url = "https://discord.com/channels/537817462272557057/1101949941712171078/1101950570035691530";
242
+ const { guildId, channelId, messageId } = getMessageUrlInfo(url);
243
+ console.log(guildId); // 537817462272557057
244
+ console.log(channelId); // 1101949941712171078
245
+ console.log(messageId); // 1101950570035691530
246
+ ```
247
+ ## Commands
248
+ Find a command easily
113
249
  ```ts
114
- const { guild } = interaction
250
+ import { findCommand } from "@magicyan/discord";
115
251
 
116
- const role = findChannel(guild).byName("Administrator") // Role | undefined
252
+ function run(interaction: ChatInputCommandInteraction<"cached">){
253
+ const { client } = interaction;
254
+ const command = findCommand(client).byName("register");
255
+ command; // ApplicationCommand | undefined
256
+ }
117
257
  ```
118
258
 
119
- Function to create embed asset
120
- If the method used to obtain a url returns null or undefined the function will set undefined in the image property
259
+ ## Emojis
260
+ Find a emoji easily
121
261
  ```ts
122
- const embed = new EmbedBuilder({
123
- image: createEmbedAsset(guild.iconURL()) // { url: guild.iconUrl() } | undefined
124
- })
262
+ import { findEmoji } from "@magicyan/discord";
263
+
264
+ function run(interaction: ChatInputCommandInteraction<"cached">){
265
+ const { client } = interaction;
266
+ const emoji = findEmoji(client).byName("discord");
267
+ emoji; // GuildEmoji | undefined
268
+ }
125
269
  ```
126
270
 
127
- When passing an attachment to the function, it will return the url with local attachments
271
+ ## Regex
272
+ Extract the id of any mention
128
273
  ```ts
129
- const image = new AttachmentBuilder(buffer, { name: "myImage.png" });
274
+ import { extractMentionId } from "@magicyan/discord";
130
275
 
131
- const embed = new EmbedBuilder({
132
- image: createEmbedAsset(image) // { url: attachment://myImage.png }
133
- });
276
+ const user = "<@264620632644255745>";
277
+ const channel = "<#1068689068256403457>";
278
+ const role = "<@&929925182796226632>";
134
279
 
135
- channel.send({ embeds: [embed], files: [image]})
280
+ extractMentionId(user) // 264620632644255745
281
+ extractMentionId(channel) // 1068689068256403457
282
+ extractMentionId(role) // 929925182796226632
136
283
  ```
@@ -60,6 +60,9 @@ function findChannel(guild, type) {
60
60
  };
61
61
  }
62
62
  function getChannelUrlInfo(url) {
63
+ const regex = new RegExp(/^https:\/\/discord\.com\/channels\/\d+\/\d+$/);
64
+ if (!regex.test(url))
65
+ return {};
63
66
  const [channelId, guildId] = url.split("/").reverse();
64
67
  return { channelId, guildId };
65
68
  }
@@ -58,6 +58,9 @@ function findChannel(guild, type) {
58
58
  };
59
59
  }
60
60
  function getChannelUrlInfo(url) {
61
+ const regex = new RegExp(/^https:\/\/discord\.com\/channels\/\d+\/\d+$/);
62
+ if (!regex.test(url))
63
+ return {};
61
64
  const [channelId, guildId] = url.split("/").reverse();
62
65
  return { channelId, guildId };
63
66
  }
@@ -10,55 +10,6 @@ function createLinkButton(data) {
10
10
  data.label = data.url;
11
11
  return new discord_js.ButtonBuilder({ style: discord_js.ButtonStyle.Link, ...data });
12
12
  }
13
- function createComponentsManager(components) {
14
- const buttons = components.flatMap(
15
- (row) => row.components.filter((c) => c.type === discord_js.ComponentType.Button)
16
- );
17
- const stringSelects = components.flatMap(
18
- (row) => row.components.filter((c) => c.type === discord_js.ComponentType.StringSelect)
19
- );
20
- const userSelects = components.flatMap(
21
- (row) => row.components.filter((c) => c.type === discord_js.ComponentType.UserSelect)
22
- );
23
- const channelSelects = components.flatMap(
24
- (row) => row.components.filter((c) => c.type === discord_js.ComponentType.ChannelSelect)
25
- );
26
- const roleSelects = components.flatMap(
27
- (row) => row.components.filter((c) => c.type === discord_js.ComponentType.RoleSelect)
28
- );
29
- const mentionableSelects = components.flatMap(
30
- (row) => row.components.filter((c) => c.type === discord_js.ComponentType.MentionableSelect)
31
- );
32
- return {
33
- getButton(customId) {
34
- return buttons.find((b) => b.customId === customId);
35
- },
36
- getStringSelect(customId) {
37
- return stringSelects.find((b) => b.customId === customId);
38
- },
39
- getUserSelect(customId) {
40
- return userSelects.find((b) => b.customId === customId);
41
- },
42
- getChannelSelect(customId) {
43
- return channelSelects.find((b) => b.customId === customId);
44
- },
45
- getRoleSelect(customId) {
46
- return roleSelects.find((b) => b.customId === customId);
47
- },
48
- getMentionableSelect(customId) {
49
- return mentionableSelects.find((b) => b.customId === customId);
50
- },
51
- resolved: {
52
- buttons,
53
- stringSelects,
54
- userSelects,
55
- channelSelects,
56
- roleSelects,
57
- mentionableSelects
58
- }
59
- };
60
- }
61
13
 
62
- exports.createComponentsManager = createComponentsManager;
63
14
  exports.createLinkButton = createLinkButton;
64
15
  exports.createRow = createRow;
@@ -1,4 +1,4 @@
1
- import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ComponentType } from 'discord.js';
1
+ import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from 'discord.js';
2
2
 
3
3
  function createRow(...components) {
4
4
  return new ActionRowBuilder({ components });
@@ -8,53 +8,5 @@ function createLinkButton(data) {
8
8
  data.label = data.url;
9
9
  return new ButtonBuilder({ style: ButtonStyle.Link, ...data });
10
10
  }
11
- function createComponentsManager(components) {
12
- const buttons = components.flatMap(
13
- (row) => row.components.filter((c) => c.type === ComponentType.Button)
14
- );
15
- const stringSelects = components.flatMap(
16
- (row) => row.components.filter((c) => c.type === ComponentType.StringSelect)
17
- );
18
- const userSelects = components.flatMap(
19
- (row) => row.components.filter((c) => c.type === ComponentType.UserSelect)
20
- );
21
- const channelSelects = components.flatMap(
22
- (row) => row.components.filter((c) => c.type === ComponentType.ChannelSelect)
23
- );
24
- const roleSelects = components.flatMap(
25
- (row) => row.components.filter((c) => c.type === ComponentType.RoleSelect)
26
- );
27
- const mentionableSelects = components.flatMap(
28
- (row) => row.components.filter((c) => c.type === ComponentType.MentionableSelect)
29
- );
30
- return {
31
- getButton(customId) {
32
- return buttons.find((b) => b.customId === customId);
33
- },
34
- getStringSelect(customId) {
35
- return stringSelects.find((b) => b.customId === customId);
36
- },
37
- getUserSelect(customId) {
38
- return userSelects.find((b) => b.customId === customId);
39
- },
40
- getChannelSelect(customId) {
41
- return channelSelects.find((b) => b.customId === customId);
42
- },
43
- getRoleSelect(customId) {
44
- return roleSelects.find((b) => b.customId === customId);
45
- },
46
- getMentionableSelect(customId) {
47
- return mentionableSelects.find((b) => b.customId === customId);
48
- },
49
- resolved: {
50
- buttons,
51
- stringSelects,
52
- userSelects,
53
- channelSelects,
54
- roleSelects,
55
- mentionableSelects
56
- }
57
- };
58
- }
59
11
 
60
- export { createComponentsManager, createLinkButton, createRow };
12
+ export { createLinkButton, createRow };
@@ -7,9 +7,9 @@ function createEmbedAsset(source, options) {
7
7
  return { url: `attachment://${source.name}`, ...options };
8
8
  }
9
9
  if (source && typeof source === "object" && "url" in source) {
10
- return source;
10
+ return Object.assign(source, options ?? (options = {}));
11
11
  }
12
- return source ? { url: source, ...options } : void 0;
12
+ return source ? Object.assign({ url: source }, options) : void 0;
13
13
  }
14
14
 
15
15
  exports.createEmbedAsset = createEmbedAsset;
@@ -5,9 +5,9 @@ function createEmbedAsset(source, options) {
5
5
  return { url: `attachment://${source.name}`, ...options };
6
6
  }
7
7
  if (source && typeof source === "object" && "url" in source) {
8
- return source;
8
+ return Object.assign(source, options ?? (options = {}));
9
9
  }
10
- return source ? { url: source, ...options } : void 0;
10
+ return source ? Object.assign({ url: source }, options) : void 0;
11
11
  }
12
12
 
13
13
  export { createEmbedAsset };
@@ -1,30 +1,33 @@
1
1
  'use strict';
2
2
 
3
- function createEmbedAuthor(options) {
4
- const { prefix = "", suffix = "", url, iconURL } = options;
5
- const { size = 512, extension, forceStatic } = options;
6
- const avatarOptions = { size, extension, forceStatic };
7
- if ("member" in options) {
8
- const { member, property: property2 = "displayName" } = options;
9
- const name = {
10
- id: member.id,
11
- username: member.user.username,
12
- displayName: member.displayName,
13
- globalName: member.user.globalName,
14
- nickname: member.nickname
15
- }[property2] ?? member.displayName;
16
- return {
17
- name: `${prefix}${name}${suffix}`,
18
- url,
19
- iconURL: iconURL || member.displayAvatarURL(avatarOptions)
20
- };
3
+ const discord_js = require('discord.js');
4
+
5
+ function createEmbedAuthor(type, options) {
6
+ const { prefix = "", suffix = "", url, iconURL: icon, extension, forceStatic, size = 1024 } = options ?? {};
7
+ let name = "";
8
+ let iconURL = icon;
9
+ const imageOptions = { extension, forceStatic, size };
10
+ switch (true) {
11
+ case type instanceof discord_js.User: {
12
+ const { property = "displayName" } = options ?? {};
13
+ name = type[property] ?? type.displayName;
14
+ iconURL = type.displayAvatarURL(imageOptions);
15
+ break;
16
+ }
17
+ case type instanceof discord_js.GuildMember: {
18
+ const { property = "displayName" } = options ?? {};
19
+ name = (property == "username" || property == "globalName" ? type.user[property] : type[property]) ?? type.displayName;
20
+ iconURL = type.displayAvatarURL(imageOptions);
21
+ break;
22
+ }
23
+ case type instanceof discord_js.Guild: {
24
+ const { property = "name" } = options ?? {};
25
+ name = type[property];
26
+ iconURL = type.iconURL(imageOptions) ?? void 0;
27
+ break;
28
+ }
21
29
  }
22
- const { property = "displayName", user } = options;
23
- return {
24
- name: `${prefix}${options.user[property]}${suffix}`,
25
- url,
26
- iconURL: iconURL || user.displayAvatarURL(avatarOptions)
27
- };
30
+ return { name: `${prefix}${name}${suffix}`, url: url ?? void 0, iconURL };
28
31
  }
29
32
 
30
33
  exports.createEmbedAuthor = createEmbedAuthor;
@@ -1,28 +1,31 @@
1
- function createEmbedAuthor(options) {
2
- const { prefix = "", suffix = "", url, iconURL } = options;
3
- const { size = 512, extension, forceStatic } = options;
4
- const avatarOptions = { size, extension, forceStatic };
5
- if ("member" in options) {
6
- const { member, property: property2 = "displayName" } = options;
7
- const name = {
8
- id: member.id,
9
- username: member.user.username,
10
- displayName: member.displayName,
11
- globalName: member.user.globalName,
12
- nickname: member.nickname
13
- }[property2] ?? member.displayName;
14
- return {
15
- name: `${prefix}${name}${suffix}`,
16
- url,
17
- iconURL: iconURL || member.displayAvatarURL(avatarOptions)
18
- };
1
+ import { Guild, GuildMember, User } from 'discord.js';
2
+
3
+ function createEmbedAuthor(type, options) {
4
+ const { prefix = "", suffix = "", url, iconURL: icon, extension, forceStatic, size = 1024 } = options ?? {};
5
+ let name = "";
6
+ let iconURL = icon;
7
+ const imageOptions = { extension, forceStatic, size };
8
+ switch (true) {
9
+ case type instanceof User: {
10
+ const { property = "displayName" } = options ?? {};
11
+ name = type[property] ?? type.displayName;
12
+ iconURL = type.displayAvatarURL(imageOptions);
13
+ break;
14
+ }
15
+ case type instanceof GuildMember: {
16
+ const { property = "displayName" } = options ?? {};
17
+ name = (property == "username" || property == "globalName" ? type.user[property] : type[property]) ?? type.displayName;
18
+ iconURL = type.displayAvatarURL(imageOptions);
19
+ break;
20
+ }
21
+ case type instanceof Guild: {
22
+ const { property = "name" } = options ?? {};
23
+ name = type[property];
24
+ iconURL = type.iconURL(imageOptions) ?? void 0;
25
+ break;
26
+ }
19
27
  }
20
- const { property = "displayName", user } = options;
21
- return {
22
- name: `${prefix}${options.user[property]}${suffix}`,
23
- url,
24
- iconURL: iconURL || user.displayAvatarURL(avatarOptions)
25
- };
28
+ return { name: `${prefix}${name}${suffix}`, url: url ?? void 0, iconURL };
26
29
  }
27
30
 
28
31
  export { createEmbedAuthor };