simple-discord-bot.js 0.1.3 → 0.2.0
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 +354 -0
- package/api.js +63 -11
- package/client.js +437 -62
- package/gateway.js +32 -14
- package/index.js +9 -1
- package/package.json +1 -1
- package/structures/ActionRowBuilder.js +42 -0
- package/structures/ButtonBuilder.js +50 -0
- package/structures/EmbedBuilder.js +34 -0
- package/structures/Message.js +37 -6
- package/structures/SelectMenuBuilder.js +68 -0
package/README.md
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
simple-discord-bot.js
|
|
2
|
+
|
|
3
|
+
""npm version" (https://img.shields.io/npm/v/simple-discord-bot.js.svg)" (https://www.npmjs.com/package/simple-discord-bot.js)
|
|
4
|
+
""npm downloads" (https://img.shields.io/npm/dm/simple-discord-bot.js.svg)" (https://www.npmjs.com/package/simple-discord-bot.js)
|
|
5
|
+
""License" (https://img.shields.io/npm/l/simple-discord-bot.js.svg)" (https://www.npmjs.com/package/simple-discord-bot.js)
|
|
6
|
+
""Node.js" (https://img.shields.io/badge/Node.js-18%2B-brightgreen.svg)" (https://nodejs.org/)
|
|
7
|
+
|
|
8
|
+
A simple and lightweight Discord bot library for Node.js
|
|
9
|
+
|
|
10
|
+
Built to make Discord bot development easier while keeping the API simple and beginner friendly
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
✨ Features
|
|
15
|
+
|
|
16
|
+
- ⚡ Lightweight
|
|
17
|
+
- 🧩 Simple API
|
|
18
|
+
- 🤖 Discord bot support
|
|
19
|
+
- 💬 Message events
|
|
20
|
+
- ⚙️ Slash commands
|
|
21
|
+
- 📝 Slash command options
|
|
22
|
+
- 🎨 EmbedBuilder
|
|
23
|
+
- 🔐 Permission checking
|
|
24
|
+
- 💓 Gateway heartbeat
|
|
25
|
+
- 🛑 Clean bot shutdown
|
|
26
|
+
- 📦 Available through npm
|
|
27
|
+
- 🟢 Easy to learn
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
📦 Installation
|
|
32
|
+
|
|
33
|
+
Install the latest version with npm
|
|
34
|
+
|
|
35
|
+
npm install simple-discord-bot.js
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
🚀 Quick Start
|
|
40
|
+
|
|
41
|
+
Create a simple bot in just a few lines
|
|
42
|
+
|
|
43
|
+
const { Client } = require("simple-discord-bot.js")
|
|
44
|
+
|
|
45
|
+
const client = new Client()
|
|
46
|
+
|
|
47
|
+
client.command("ping", interaction => {
|
|
48
|
+
interaction.reply("Pong!")
|
|
49
|
+
}, {
|
|
50
|
+
description: "Replies with Pong!"
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
client.on("ready", () => {
|
|
54
|
+
console.log("Bot is online!")
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
client.login("YOUR_BOT_TOKEN")
|
|
58
|
+
|
|
59
|
+
Start your bot
|
|
60
|
+
|
|
61
|
+
node index.js
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
⚙️ Slash Commands
|
|
66
|
+
|
|
67
|
+
Create commands with "client.command()"
|
|
68
|
+
|
|
69
|
+
client.command("hello", interaction => {
|
|
70
|
+
interaction.reply("Hello!")
|
|
71
|
+
}, {
|
|
72
|
+
description: "Says hello"
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
🧩 Command Options
|
|
78
|
+
|
|
79
|
+
Commands can have options
|
|
80
|
+
|
|
81
|
+
client.command("say", interaction => {
|
|
82
|
+
interaction.reply(interaction.options.message)
|
|
83
|
+
}, {
|
|
84
|
+
description: "Make the bot say something",
|
|
85
|
+
options: [
|
|
86
|
+
{
|
|
87
|
+
name: "message",
|
|
88
|
+
description: "The message to send",
|
|
89
|
+
type: 3,
|
|
90
|
+
required: true
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
The option can then be accessed with
|
|
96
|
+
|
|
97
|
+
interaction.options.message
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
🎨 Embeds
|
|
102
|
+
|
|
103
|
+
Create beautiful Discord embeds with "EmbedBuilder"
|
|
104
|
+
|
|
105
|
+
const { EmbedBuilder } = require("simple-discord-bot.js")
|
|
106
|
+
|
|
107
|
+
const embed = new EmbedBuilder()
|
|
108
|
+
.setTitle("Hello")
|
|
109
|
+
.setDescription("This is an embed!")
|
|
110
|
+
.setColor("5865F2")
|
|
111
|
+
.setFooter("Made with SimpleDiscord.js")
|
|
112
|
+
.setTimestamp()
|
|
113
|
+
|
|
114
|
+
interaction.reply(embed)
|
|
115
|
+
|
|
116
|
+
Embed Methods
|
|
117
|
+
|
|
118
|
+
Title
|
|
119
|
+
|
|
120
|
+
.setTitle("Hello")
|
|
121
|
+
|
|
122
|
+
Description
|
|
123
|
+
|
|
124
|
+
.setDescription("This is my description")
|
|
125
|
+
|
|
126
|
+
Color
|
|
127
|
+
|
|
128
|
+
Hex colors are supported
|
|
129
|
+
|
|
130
|
+
.setColor("FF0000")
|
|
131
|
+
|
|
132
|
+
URL
|
|
133
|
+
|
|
134
|
+
.setURL("https://example.com")
|
|
135
|
+
|
|
136
|
+
Footer
|
|
137
|
+
|
|
138
|
+
.setFooter("Made with SimpleDiscord.js")
|
|
139
|
+
|
|
140
|
+
Footer Icon
|
|
141
|
+
|
|
142
|
+
.setFooter(
|
|
143
|
+
"Made with SimpleDiscord.js",
|
|
144
|
+
"https://example.com/icon.png"
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
Author
|
|
148
|
+
|
|
149
|
+
.setAuthor("SimpleBot")
|
|
150
|
+
|
|
151
|
+
Author Icon
|
|
152
|
+
|
|
153
|
+
.setAuthor(
|
|
154
|
+
"SimpleBot",
|
|
155
|
+
"https://example.com/icon.png"
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
Thumbnail
|
|
159
|
+
|
|
160
|
+
.setThumbnail("https://example.com/image.png")
|
|
161
|
+
|
|
162
|
+
Image
|
|
163
|
+
|
|
164
|
+
.setImage("https://example.com/image.png")
|
|
165
|
+
|
|
166
|
+
Timestamp
|
|
167
|
+
|
|
168
|
+
.setTimestamp()
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
🔐 Permissions
|
|
173
|
+
|
|
174
|
+
Check Discord permissions easily
|
|
175
|
+
|
|
176
|
+
client.command("admin", interaction => {
|
|
177
|
+
if (!interaction.member?.permissions.has("Administrator")) {
|
|
178
|
+
return interaction.reply("You need Administrator")
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
interaction.reply("You have Administrator permission!")
|
|
182
|
+
}, {
|
|
183
|
+
description: "Administrator only command"
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
💬 Messages
|
|
189
|
+
|
|
190
|
+
Listen for messages
|
|
191
|
+
|
|
192
|
+
client.on("message", message => {
|
|
193
|
+
console.log(message.content)
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
Reply to messages
|
|
197
|
+
|
|
198
|
+
message.reply("Hello!")
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
📡 Events
|
|
203
|
+
|
|
204
|
+
SimpleDiscord.js currently supports:
|
|
205
|
+
|
|
206
|
+
Event| Description
|
|
207
|
+
"ready"| Bot is ready
|
|
208
|
+
"message"| A message was created
|
|
209
|
+
"error"| Gateway error
|
|
210
|
+
"disconnect"| Bot disconnected
|
|
211
|
+
|
|
212
|
+
Example
|
|
213
|
+
|
|
214
|
+
client.on("ready", () => {
|
|
215
|
+
console.log("Bot is online!")
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
🛠️ API
|
|
221
|
+
|
|
222
|
+
Client
|
|
223
|
+
|
|
224
|
+
const { Client } = require("simple-discord-bot.js")
|
|
225
|
+
|
|
226
|
+
const client = new Client()
|
|
227
|
+
|
|
228
|
+
"client.login(token)"
|
|
229
|
+
|
|
230
|
+
Connect your bot to Discord
|
|
231
|
+
|
|
232
|
+
client.login("YOUR_BOT_TOKEN")
|
|
233
|
+
|
|
234
|
+
"client.command(name, handler, options)"
|
|
235
|
+
|
|
236
|
+
Create a slash command
|
|
237
|
+
|
|
238
|
+
client.command(
|
|
239
|
+
"ping",
|
|
240
|
+
interaction => {
|
|
241
|
+
interaction.reply("Pong!")
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
description: "Replies with Pong!"
|
|
245
|
+
}
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
"client.destroy()"
|
|
249
|
+
|
|
250
|
+
Disconnect the bot
|
|
251
|
+
|
|
252
|
+
client.destroy()
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
📊 Current Status
|
|
257
|
+
|
|
258
|
+
SimpleDiscord.js is currently in early development
|
|
259
|
+
|
|
260
|
+
Current version:
|
|
261
|
+
|
|
262
|
+
0.1.2
|
|
263
|
+
|
|
264
|
+
The API may change as the library develops
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
🗺️ Roadmap
|
|
269
|
+
|
|
270
|
+
✅ Completed
|
|
271
|
+
|
|
272
|
+
- [x] Discord Gateway connection
|
|
273
|
+
- [x] Gateway heartbeat
|
|
274
|
+
- [x] Bot login
|
|
275
|
+
- [x] Clean shutdown
|
|
276
|
+
- [x] Ready event
|
|
277
|
+
- [x] Message events
|
|
278
|
+
- [x] Message replies
|
|
279
|
+
- [x] Slash commands
|
|
280
|
+
- [x] Slash command options
|
|
281
|
+
- [x] Permission checking
|
|
282
|
+
- [x] EmbedBuilder
|
|
283
|
+
- [x] npm publishing
|
|
284
|
+
|
|
285
|
+
🚧 Planned
|
|
286
|
+
|
|
287
|
+
- [ ] Embed fields
|
|
288
|
+
- [ ] Buttons
|
|
289
|
+
- [ ] Select menus
|
|
290
|
+
- [ ] More interaction types
|
|
291
|
+
- [ ] Channel objects
|
|
292
|
+
- [ ] Guild objects
|
|
293
|
+
- [ ] User objects
|
|
294
|
+
- [ ] Message editing
|
|
295
|
+
- [ ] Message deletion
|
|
296
|
+
- [ ] More permission helpers
|
|
297
|
+
- [ ] Better error handling
|
|
298
|
+
- [ ] Automatic reconnection
|
|
299
|
+
- [ ] Gateway resume support
|
|
300
|
+
- [ ] More Discord API features
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
📚 Why SimpleDiscord.js?
|
|
305
|
+
|
|
306
|
+
Discord libraries can become complicated when you're just starting
|
|
307
|
+
|
|
308
|
+
SimpleDiscord.js focuses on keeping things straightforward
|
|
309
|
+
|
|
310
|
+
Instead of learning a huge API you can start with:
|
|
311
|
+
|
|
312
|
+
const { Client } = require("simple-discord-bot.js")
|
|
313
|
+
|
|
314
|
+
const client = new Client()
|
|
315
|
+
|
|
316
|
+
client.command("ping", interaction => {
|
|
317
|
+
interaction.reply("Pong!")
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
client.login("YOUR_BOT_TOKEN")
|
|
321
|
+
|
|
322
|
+
Simple
|
|
323
|
+
|
|
324
|
+
Lightweight
|
|
325
|
+
|
|
326
|
+
Beginner friendly
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
📦 npm
|
|
331
|
+
|
|
332
|
+
Install the package from npm
|
|
333
|
+
|
|
334
|
+
npm install simple-discord-bot.js
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
🤝 Contributing
|
|
339
|
+
|
|
340
|
+
Contributions and suggestions are welcome
|
|
341
|
+
|
|
342
|
+
If you find a bug or have an idea for a feature you can open an issue or submit a pull request
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
📄 License
|
|
347
|
+
|
|
348
|
+
MIT License
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
Made with ❤️ and JavaScript
|
|
353
|
+
|
|
354
|
+
simple-discord-bot.js
|
package/api.js
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
const https = require("https")
|
|
2
2
|
|
|
3
|
+
class DiscordAPIError extends Error {
|
|
4
|
+
constructor(message, options = {}) {
|
|
5
|
+
super(message)
|
|
6
|
+
|
|
7
|
+
this.name = "DiscordAPIError"
|
|
8
|
+
this.code = options.code || null
|
|
9
|
+
this.status = options.status || null
|
|
10
|
+
this.method = options.method || null
|
|
11
|
+
this.path = options.path || null
|
|
12
|
+
this.errors = options.errors || null
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
3
16
|
class API {
|
|
4
17
|
constructor(token) {
|
|
5
18
|
this.token = token
|
|
@@ -7,7 +20,10 @@ class API {
|
|
|
7
20
|
|
|
8
21
|
request(method, path, body = null) {
|
|
9
22
|
return new Promise((resolve, reject) => {
|
|
10
|
-
const data =
|
|
23
|
+
const data =
|
|
24
|
+
body !== null
|
|
25
|
+
? JSON.stringify(body)
|
|
26
|
+
: null
|
|
11
27
|
|
|
12
28
|
const headers = {
|
|
13
29
|
Authorization: `Bot ${this.token}`,
|
|
@@ -15,7 +31,8 @@ class API {
|
|
|
15
31
|
}
|
|
16
32
|
|
|
17
33
|
if (data) {
|
|
18
|
-
headers["Content-Length"] =
|
|
34
|
+
headers["Content-Length"] =
|
|
35
|
+
Buffer.byteLength(data)
|
|
19
36
|
}
|
|
20
37
|
|
|
21
38
|
const req = https.request({
|
|
@@ -31,25 +48,57 @@ class API {
|
|
|
31
48
|
})
|
|
32
49
|
|
|
33
50
|
res.on("end", () => {
|
|
51
|
+
let parsed
|
|
52
|
+
|
|
34
53
|
try {
|
|
35
|
-
|
|
54
|
+
parsed =
|
|
55
|
+
result
|
|
56
|
+
? JSON.parse(result)
|
|
57
|
+
: null
|
|
36
58
|
} catch {
|
|
37
|
-
|
|
59
|
+
parsed = result
|
|
38
60
|
}
|
|
61
|
+
|
|
62
|
+
if (
|
|
63
|
+
res.statusCode < 200 ||
|
|
64
|
+
res.statusCode >= 300
|
|
65
|
+
) {
|
|
66
|
+
const message =
|
|
67
|
+
parsed?.message ||
|
|
68
|
+
"Discord API request failed."
|
|
69
|
+
|
|
70
|
+
const error =
|
|
71
|
+
new DiscordAPIError(
|
|
72
|
+
message,
|
|
73
|
+
{
|
|
74
|
+
code: parsed?.code,
|
|
75
|
+
status: res.statusCode,
|
|
76
|
+
method,
|
|
77
|
+
path,
|
|
78
|
+
errors: parsed?.errors
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
reject(error)
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
resolve(parsed)
|
|
39
87
|
})
|
|
40
88
|
})
|
|
41
89
|
|
|
42
|
-
req.on("error",
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
req.write(data)
|
|
46
|
-
}
|
|
90
|
+
req.on("error", error => {
|
|
91
|
+
reject(error)
|
|
92
|
+
})
|
|
47
93
|
|
|
48
|
-
req.end()
|
|
94
|
+
req.end(data || undefined)
|
|
49
95
|
})
|
|
50
96
|
}
|
|
51
97
|
|
|
52
|
-
registerCommands(
|
|
98
|
+
registerCommands(
|
|
99
|
+
applicationId,
|
|
100
|
+
commands
|
|
101
|
+
) {
|
|
53
102
|
return this.request(
|
|
54
103
|
"PUT",
|
|
55
104
|
`/applications/${applicationId}/commands`,
|
|
@@ -58,4 +107,7 @@ class API {
|
|
|
58
107
|
}
|
|
59
108
|
}
|
|
60
109
|
|
|
110
|
+
API.DiscordAPIError =
|
|
111
|
+
DiscordAPIError
|
|
112
|
+
|
|
61
113
|
module.exports = API
|
package/client.js
CHANGED
|
@@ -46,15 +46,20 @@ class Permissions {
|
|
|
46
46
|
has(permission) {
|
|
47
47
|
const flag = PermissionFlags[permission]
|
|
48
48
|
|
|
49
|
-
if (flag
|
|
49
|
+
if (!flag) {
|
|
50
50
|
return false
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
if (
|
|
53
|
+
if (
|
|
54
|
+
(this.bitfield &
|
|
55
|
+
PermissionFlags.Administrator) !== 0n
|
|
56
|
+
) {
|
|
54
57
|
return true
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
return (
|
|
60
|
+
return (
|
|
61
|
+
(this.bitfield & flag) !== 0n
|
|
62
|
+
)
|
|
58
63
|
}
|
|
59
64
|
}
|
|
60
65
|
|
|
@@ -64,113 +69,483 @@ class Client extends EventEmitter {
|
|
|
64
69
|
|
|
65
70
|
this.token = null
|
|
66
71
|
this.user = null
|
|
72
|
+
this.applicationId = null
|
|
67
73
|
this.api = null
|
|
68
74
|
this.gateway = new Gateway(this)
|
|
69
75
|
this.commands = new Map()
|
|
76
|
+
|
|
70
77
|
this.stopping = false
|
|
78
|
+
this.ready = false
|
|
79
|
+
this.readyAt = null
|
|
71
80
|
|
|
72
81
|
this.on("rawMessage", data => {
|
|
73
|
-
const message =
|
|
74
|
-
|
|
82
|
+
const message =
|
|
83
|
+
new Message(this, data)
|
|
84
|
+
|
|
85
|
+
this.emit(
|
|
86
|
+
"message",
|
|
87
|
+
message
|
|
88
|
+
)
|
|
75
89
|
})
|
|
76
90
|
|
|
77
91
|
this.on("rawInteraction", data => {
|
|
78
|
-
if (data.type
|
|
92
|
+
if (data.type === 2) {
|
|
93
|
+
this.handleCommandInteraction(
|
|
94
|
+
data
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (data.type === 3) {
|
|
101
|
+
this.handleComponentInteraction(
|
|
102
|
+
data
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
this.on("rawReady", async data => {
|
|
108
|
+
this.user = data.user
|
|
79
109
|
|
|
80
|
-
|
|
110
|
+
this.applicationId =
|
|
111
|
+
data.application?.id ||
|
|
112
|
+
data.user?.id
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
await this.syncCommands()
|
|
116
|
+
|
|
117
|
+
this.ready = true
|
|
118
|
+
this.readyAt = Date.now()
|
|
119
|
+
|
|
120
|
+
this.emit(
|
|
121
|
+
"ready",
|
|
122
|
+
data
|
|
123
|
+
)
|
|
124
|
+
} catch (error) {
|
|
125
|
+
this.emit(
|
|
126
|
+
"error",
|
|
127
|
+
error
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
this.on("disconnect", () => {
|
|
133
|
+
this.ready = false
|
|
134
|
+
this.readyAt = null
|
|
135
|
+
})
|
|
81
136
|
|
|
82
|
-
|
|
137
|
+
process.on("SIGINT", () => {
|
|
138
|
+
if (this.stopping) return
|
|
83
139
|
|
|
84
|
-
|
|
140
|
+
this.stopping = true
|
|
85
141
|
|
|
86
|
-
|
|
87
|
-
id: data.id,
|
|
88
|
-
token: data.token,
|
|
142
|
+
this.destroy()
|
|
89
143
|
|
|
90
|
-
|
|
144
|
+
setTimeout(() => {
|
|
145
|
+
process.exit(0)
|
|
146
|
+
}, 1000)
|
|
147
|
+
})
|
|
148
|
+
}
|
|
91
149
|
|
|
92
|
-
|
|
150
|
+
isReady() {
|
|
151
|
+
return this.ready
|
|
152
|
+
}
|
|
93
153
|
|
|
94
|
-
|
|
95
|
-
|
|
154
|
+
get uptime() {
|
|
155
|
+
if (!this.readyAt) {
|
|
156
|
+
return null
|
|
157
|
+
}
|
|
96
158
|
|
|
97
|
-
|
|
98
|
-
|
|
159
|
+
return Date.now() - this.readyAt
|
|
160
|
+
}
|
|
99
161
|
|
|
100
|
-
|
|
162
|
+
createInteraction(data, type) {
|
|
163
|
+
const member = data.member
|
|
101
164
|
|
|
102
|
-
|
|
165
|
+
const interaction = {
|
|
166
|
+
id: data.id,
|
|
167
|
+
token: data.token,
|
|
168
|
+
type: type,
|
|
103
169
|
|
|
104
|
-
|
|
170
|
+
user:
|
|
171
|
+
member?.user ||
|
|
172
|
+
data.user,
|
|
105
173
|
|
|
106
|
-
|
|
107
|
-
|
|
174
|
+
member: member
|
|
175
|
+
? {
|
|
176
|
+
...member,
|
|
108
177
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
typeof content.toJSON === "function"
|
|
114
|
-
) {
|
|
115
|
-
messageData.embeds = [content.toJSON()]
|
|
116
|
-
} else if (content && typeof content === "object") {
|
|
117
|
-
Object.assign(messageData, content)
|
|
178
|
+
permissions:
|
|
179
|
+
new Permissions(
|
|
180
|
+
member.permissions
|
|
181
|
+
)
|
|
118
182
|
}
|
|
183
|
+
: null,
|
|
184
|
+
|
|
185
|
+
channelId:
|
|
186
|
+
data.channel_id,
|
|
187
|
+
|
|
188
|
+
guildId:
|
|
189
|
+
data.guild_id ||
|
|
190
|
+
null,
|
|
191
|
+
|
|
192
|
+
replied: false,
|
|
193
|
+
deferred: false,
|
|
119
194
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
195
|
+
reply: async content => {
|
|
196
|
+
return this.replyToInteraction(
|
|
197
|
+
data,
|
|
198
|
+
content,
|
|
199
|
+
interaction
|
|
200
|
+
)
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
deferReply: async () => {
|
|
204
|
+
if (
|
|
205
|
+
interaction.replied ||
|
|
206
|
+
interaction.deferred
|
|
207
|
+
) {
|
|
208
|
+
throw new Error(
|
|
209
|
+
"This interaction has already been responded to."
|
|
127
210
|
)
|
|
128
211
|
}
|
|
212
|
+
|
|
213
|
+
await this.api.request(
|
|
214
|
+
"POST",
|
|
215
|
+
`/interactions/${data.id}/${data.token}/callback`,
|
|
216
|
+
{
|
|
217
|
+
type: 5,
|
|
218
|
+
data: {}
|
|
219
|
+
}
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
interaction.deferred = true
|
|
223
|
+
|
|
224
|
+
return true
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
editReply: async content => {
|
|
228
|
+
if (
|
|
229
|
+
!interaction.replied &&
|
|
230
|
+
!interaction.deferred
|
|
231
|
+
) {
|
|
232
|
+
throw new Error(
|
|
233
|
+
"You must reply or defer the interaction first."
|
|
234
|
+
)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const messageData =
|
|
238
|
+
this.formatInteractionContent(
|
|
239
|
+
content
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
return this.api.request(
|
|
243
|
+
"PATCH",
|
|
244
|
+
`/webhooks/${this.applicationId}/${data.token}/messages/@original`,
|
|
245
|
+
messageData
|
|
246
|
+
)
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
deleteReply: async () => {
|
|
250
|
+
if (
|
|
251
|
+
!interaction.replied &&
|
|
252
|
+
!interaction.deferred
|
|
253
|
+
) {
|
|
254
|
+
throw new Error(
|
|
255
|
+
"You must reply or defer the interaction first."
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
await this.api.request(
|
|
260
|
+
"DELETE",
|
|
261
|
+
`/webhooks/${this.applicationId}/${data.token}/messages/@original`
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
return true
|
|
129
265
|
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return interaction
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
formatInteractionContent(content) {
|
|
272
|
+
const messageData = {}
|
|
273
|
+
|
|
274
|
+
if (typeof content === "string") {
|
|
275
|
+
messageData.content =
|
|
276
|
+
content
|
|
277
|
+
} else if (
|
|
278
|
+
content &&
|
|
279
|
+
typeof content.toJSON === "function"
|
|
280
|
+
) {
|
|
281
|
+
messageData.embeds = [
|
|
282
|
+
content.toJSON()
|
|
283
|
+
]
|
|
284
|
+
} else if (
|
|
285
|
+
content &&
|
|
286
|
+
typeof content === "object"
|
|
287
|
+
) {
|
|
288
|
+
Object.assign(
|
|
289
|
+
messageData,
|
|
290
|
+
content
|
|
291
|
+
)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return messageData
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
handleCommandInteraction(data) {
|
|
298
|
+
const command =
|
|
299
|
+
this.commands.get(
|
|
300
|
+
data.data.name
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
if (!command) return
|
|
304
|
+
|
|
305
|
+
const interaction =
|
|
306
|
+
this.createInteraction(
|
|
307
|
+
data,
|
|
308
|
+
"command"
|
|
309
|
+
)
|
|
130
310
|
|
|
131
|
-
|
|
132
|
-
|
|
311
|
+
interaction.commandName =
|
|
312
|
+
data.data.name
|
|
313
|
+
|
|
314
|
+
interaction.options = {}
|
|
315
|
+
|
|
316
|
+
for (
|
|
317
|
+
const option of
|
|
318
|
+
data.data.options || []
|
|
319
|
+
) {
|
|
320
|
+
interaction.options[
|
|
321
|
+
option.name
|
|
322
|
+
] = option.value
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
try {
|
|
326
|
+
const result =
|
|
327
|
+
command.handler(
|
|
328
|
+
interaction
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
if (result?.catch) {
|
|
332
|
+
result.catch(error => {
|
|
333
|
+
this.emit(
|
|
334
|
+
"error",
|
|
335
|
+
error
|
|
336
|
+
)
|
|
337
|
+
})
|
|
133
338
|
}
|
|
339
|
+
} catch (error) {
|
|
340
|
+
this.emit(
|
|
341
|
+
"error",
|
|
342
|
+
error
|
|
343
|
+
)
|
|
344
|
+
}
|
|
345
|
+
}
|
|
134
346
|
|
|
135
|
-
|
|
136
|
-
|
|
347
|
+
handleComponentInteraction(data) {
|
|
348
|
+
const componentType =
|
|
349
|
+
data.data.component_type
|
|
137
350
|
|
|
138
|
-
|
|
139
|
-
if (this.stopping) return
|
|
351
|
+
let type = "selectMenu"
|
|
140
352
|
|
|
141
|
-
|
|
353
|
+
if (componentType === 2) {
|
|
354
|
+
type = "button"
|
|
355
|
+
}
|
|
142
356
|
|
|
143
|
-
|
|
357
|
+
const interaction =
|
|
358
|
+
this.createInteraction(
|
|
359
|
+
data,
|
|
360
|
+
type
|
|
361
|
+
)
|
|
144
362
|
|
|
145
|
-
|
|
363
|
+
interaction.componentType =
|
|
364
|
+
componentType
|
|
146
365
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
366
|
+
interaction.customId =
|
|
367
|
+
data.data.custom_id
|
|
368
|
+
|
|
369
|
+
interaction.values =
|
|
370
|
+
data.data.values || []
|
|
371
|
+
|
|
372
|
+
this.emit(
|
|
373
|
+
"interaction",
|
|
374
|
+
interaction
|
|
375
|
+
)
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
replyToInteraction(
|
|
379
|
+
data,
|
|
380
|
+
content,
|
|
381
|
+
interaction = null
|
|
382
|
+
) {
|
|
383
|
+
if (
|
|
384
|
+
interaction?.replied ||
|
|
385
|
+
interaction?.deferred
|
|
386
|
+
) {
|
|
387
|
+
return Promise.reject(
|
|
388
|
+
new Error(
|
|
389
|
+
"This interaction has already been responded to."
|
|
390
|
+
)
|
|
391
|
+
)
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const messageData =
|
|
395
|
+
this.formatInteractionContent(
|
|
396
|
+
content
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
return this.api.request(
|
|
400
|
+
"POST",
|
|
401
|
+
`/interactions/${data.id}/${data.token}/callback`,
|
|
402
|
+
{
|
|
403
|
+
type: 4,
|
|
404
|
+
data: messageData
|
|
405
|
+
}
|
|
406
|
+
).then(result => {
|
|
407
|
+
if (interaction) {
|
|
408
|
+
interaction.replied = true
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return result
|
|
150
412
|
})
|
|
151
413
|
}
|
|
152
414
|
|
|
415
|
+
async syncCommands() {
|
|
416
|
+
if (!this.applicationId) {
|
|
417
|
+
throw new Error(
|
|
418
|
+
"Application ID is not available."
|
|
419
|
+
)
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const commands = []
|
|
423
|
+
|
|
424
|
+
for (
|
|
425
|
+
const entry of
|
|
426
|
+
this.commands.values()
|
|
427
|
+
) {
|
|
428
|
+
commands.push(
|
|
429
|
+
entry.command
|
|
430
|
+
)
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const result =
|
|
434
|
+
await this.api.registerCommands(
|
|
435
|
+
this.applicationId,
|
|
436
|
+
commands
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
if (!Array.isArray(result)) {
|
|
440
|
+
throw new Error(
|
|
441
|
+
"Failed to register slash commands: " +
|
|
442
|
+
JSON.stringify(result)
|
|
443
|
+
)
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return result
|
|
447
|
+
}
|
|
448
|
+
|
|
153
449
|
login(token) {
|
|
154
450
|
this.token = token
|
|
155
451
|
this.api = new API(token)
|
|
156
452
|
|
|
157
|
-
return this.gateway.connect(
|
|
453
|
+
return this.gateway.connect(
|
|
454
|
+
token
|
|
455
|
+
)
|
|
158
456
|
}
|
|
159
457
|
|
|
160
458
|
destroy() {
|
|
161
459
|
this.gateway.destroy()
|
|
162
|
-
|
|
460
|
+
|
|
461
|
+
this.ready = false
|
|
462
|
+
this.readyAt = null
|
|
463
|
+
|
|
464
|
+
this.emit(
|
|
465
|
+
"disconnect"
|
|
466
|
+
)
|
|
163
467
|
}
|
|
164
468
|
|
|
165
|
-
command(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
469
|
+
command(
|
|
470
|
+
name,
|
|
471
|
+
handler,
|
|
472
|
+
options = {}
|
|
473
|
+
) {
|
|
474
|
+
this.commands.set(
|
|
475
|
+
name,
|
|
476
|
+
{
|
|
477
|
+
command: {
|
|
478
|
+
name: name,
|
|
479
|
+
|
|
480
|
+
description:
|
|
481
|
+
options.description ||
|
|
482
|
+
"No description",
|
|
483
|
+
|
|
484
|
+
options:
|
|
485
|
+
options.options ||
|
|
486
|
+
[]
|
|
487
|
+
},
|
|
488
|
+
|
|
489
|
+
handler: handler
|
|
490
|
+
}
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
return this
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
async removeCommand(name) {
|
|
497
|
+
const command =
|
|
498
|
+
this.commands.get(name)
|
|
499
|
+
|
|
500
|
+
if (!command) {
|
|
501
|
+
return false
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if (!this.applicationId) {
|
|
505
|
+
throw new Error(
|
|
506
|
+
"Bot must be logged in before removing a Discord slash command."
|
|
507
|
+
)
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const commands =
|
|
511
|
+
await this.api.request(
|
|
512
|
+
"GET",
|
|
513
|
+
`/applications/${this.applicationId}/commands`
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
if (!Array.isArray(commands)) {
|
|
517
|
+
throw new Error(
|
|
518
|
+
"Failed to retrieve Discord application commands."
|
|
519
|
+
)
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
const discordCommand =
|
|
523
|
+
commands.find(
|
|
524
|
+
command =>
|
|
525
|
+
command.name === name
|
|
526
|
+
)
|
|
527
|
+
|
|
528
|
+
if (discordCommand) {
|
|
529
|
+
await this.api.request(
|
|
530
|
+
"DELETE",
|
|
531
|
+
`/applications/${this.applicationId}/commands/${discordCommand.id}`
|
|
532
|
+
)
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
this.commands.delete(name)
|
|
536
|
+
|
|
537
|
+
return true
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
getCommand(name) {
|
|
541
|
+
return (
|
|
542
|
+
this.commands.get(name) ||
|
|
543
|
+
null
|
|
544
|
+
)
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
hasCommand(name) {
|
|
548
|
+
return this.commands.has(name)
|
|
174
549
|
}
|
|
175
550
|
}
|
|
176
551
|
|
package/gateway.js
CHANGED
|
@@ -13,11 +13,13 @@ class Gateway {
|
|
|
13
13
|
)
|
|
14
14
|
|
|
15
15
|
this.ws.on("open", () => {
|
|
16
|
+
console.log("Connected to Discord Gateway")
|
|
17
|
+
|
|
16
18
|
this.ws.send(JSON.stringify({
|
|
17
19
|
op: 2,
|
|
18
20
|
d: {
|
|
19
21
|
token: token,
|
|
20
|
-
intents: 33281,
|
|
22
|
+
intents: 33281 | 32768,
|
|
21
23
|
properties: {
|
|
22
24
|
os: "android",
|
|
23
25
|
browser: "SimpleDiscord.js",
|
|
@@ -28,23 +30,36 @@ class Gateway {
|
|
|
28
30
|
})
|
|
29
31
|
|
|
30
32
|
this.ws.on("message", data => {
|
|
31
|
-
|
|
33
|
+
try {
|
|
34
|
+
const packet = JSON.parse(data)
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
if (packet.op === 10) {
|
|
37
|
+
console.log("Gateway connected")
|
|
38
|
+
this.startHeartbeat(packet.d.heartbeat_interval)
|
|
39
|
+
}
|
|
36
40
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
if (packet.op === 9) {
|
|
42
|
+
console.error("Discord rejected the Gateway connection")
|
|
43
|
+
return
|
|
44
|
+
}
|
|
41
45
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
if (packet.t === "READY") {
|
|
47
|
+
this.client.user = packet.d.user
|
|
48
|
+
this.client.applicationId =
|
|
49
|
+
packet.d.application?.id ||
|
|
50
|
+
packet.d.user?.id
|
|
45
51
|
|
|
46
|
-
|
|
47
|
-
|
|
52
|
+
this.client.emit("rawReady", packet.d)
|
|
53
|
+
}
|
|
54
|
+
if (packet.t === "MESSAGE_CREATE") {
|
|
55
|
+
this.client.emit("rawMessage", packet.d)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (packet.t === "INTERACTION_CREATE") {
|
|
59
|
+
this.client.emit("rawInteraction", packet.d)
|
|
60
|
+
}
|
|
61
|
+
} catch (error) {
|
|
62
|
+
this.client.emit("error", error)
|
|
48
63
|
}
|
|
49
64
|
})
|
|
50
65
|
|
|
@@ -57,6 +72,8 @@ class Gateway {
|
|
|
57
72
|
this.ws = null
|
|
58
73
|
this.client.emit("disconnect")
|
|
59
74
|
})
|
|
75
|
+
|
|
76
|
+
return this.ws
|
|
60
77
|
}
|
|
61
78
|
|
|
62
79
|
startHeartbeat(interval) {
|
|
@@ -84,6 +101,7 @@ class Gateway {
|
|
|
84
101
|
|
|
85
102
|
if (this.ws) {
|
|
86
103
|
this.ws.close(1000, "Bot stopped")
|
|
104
|
+
this.ws = null
|
|
87
105
|
}
|
|
88
106
|
}
|
|
89
107
|
}
|
package/index.js
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
const Client = require("./client")
|
|
2
2
|
const EmbedBuilder = require("./structures/EmbedBuilder")
|
|
3
|
+
const ButtonBuilder = require("./structures/ButtonBuilder")
|
|
4
|
+
const SelectMenuBuilder = require("./structures/SelectMenuBuilder")
|
|
5
|
+
const ActionRowBuilder = require("./structures/ActionRowBuilder")
|
|
6
|
+
const API = require("./api")
|
|
3
7
|
|
|
4
8
|
module.exports = {
|
|
5
9
|
Client,
|
|
6
|
-
EmbedBuilder
|
|
10
|
+
EmbedBuilder,
|
|
11
|
+
ButtonBuilder,
|
|
12
|
+
SelectMenuBuilder,
|
|
13
|
+
ActionRowBuilder,
|
|
14
|
+
DiscordAPIError: API.DiscordAPIError
|
|
7
15
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
class ActionRowBuilder {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.data = {
|
|
4
|
+
type: 1,
|
|
5
|
+
components: []
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
addComponents(...components) {
|
|
10
|
+
for (const component of components) {
|
|
11
|
+
if (!component) continue
|
|
12
|
+
|
|
13
|
+
if (typeof component.toJSON === "function") {
|
|
14
|
+
this.data.components.push(
|
|
15
|
+
component.toJSON()
|
|
16
|
+
)
|
|
17
|
+
} else if (
|
|
18
|
+
typeof component === "object"
|
|
19
|
+
) {
|
|
20
|
+
this.data.components.push(
|
|
21
|
+
component
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return this
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
setComponents(...components) {
|
|
30
|
+
this.data.components = []
|
|
31
|
+
|
|
32
|
+
return this.addComponents(
|
|
33
|
+
...components
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
toJSON() {
|
|
38
|
+
return this.data
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = ActionRowBuilder
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
class ButtonBuilder {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.data = {
|
|
4
|
+
type: 2
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
setCustomId(customId) {
|
|
9
|
+
this.data.custom_id = customId
|
|
10
|
+
return this
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
setLabel(label) {
|
|
14
|
+
this.data.label = label
|
|
15
|
+
return this
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
setStyle(style) {
|
|
19
|
+
const styles = {
|
|
20
|
+
primary: 1,
|
|
21
|
+
secondary: 2,
|
|
22
|
+
success: 3,
|
|
23
|
+
danger: 4,
|
|
24
|
+
link: 5
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (typeof style === "string") {
|
|
28
|
+
style = styles[style.toLowerCase()]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
this.data.style = style
|
|
32
|
+
return this
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
setURL(url) {
|
|
36
|
+
this.data.url = url
|
|
37
|
+
return this
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
setDisabled(disabled = true) {
|
|
41
|
+
this.data.disabled = disabled
|
|
42
|
+
return this
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
toJSON() {
|
|
46
|
+
return this.data
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = ButtonBuilder
|
|
@@ -82,6 +82,40 @@ class EmbedBuilder {
|
|
|
82
82
|
return this
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
addField(name, value, inline = false) {
|
|
86
|
+
if (!this.data.fields) {
|
|
87
|
+
this.data.fields = []
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this.data.fields.push({
|
|
91
|
+
name: name,
|
|
92
|
+
value: value,
|
|
93
|
+
inline: inline
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
return this
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
addFields(...fields) {
|
|
100
|
+
for (const field of fields) {
|
|
101
|
+
if (
|
|
102
|
+
!field ||
|
|
103
|
+
typeof field.name !== "string" ||
|
|
104
|
+
typeof field.value !== "string"
|
|
105
|
+
) {
|
|
106
|
+
continue
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
this.addField(
|
|
110
|
+
field.name,
|
|
111
|
+
field.value,
|
|
112
|
+
field.inline || false
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return this
|
|
117
|
+
}
|
|
118
|
+
|
|
85
119
|
toJSON() {
|
|
86
120
|
return this.data
|
|
87
121
|
}
|
package/structures/Message.js
CHANGED
|
@@ -1,22 +1,53 @@
|
|
|
1
1
|
class Message {
|
|
2
2
|
constructor(client, data) {
|
|
3
3
|
this.client = client
|
|
4
|
-
|
|
5
4
|
this.id = data.id
|
|
6
|
-
this.content = data.content
|
|
5
|
+
this.content = data.content || ""
|
|
7
6
|
this.channelId = data.channel_id
|
|
8
|
-
this.guildId = data.guild_id
|
|
9
|
-
this.author = data.author
|
|
7
|
+
this.guildId = data.guild_id || null
|
|
8
|
+
this.author = data.author || null
|
|
10
9
|
}
|
|
11
10
|
|
|
12
|
-
reply(content) {
|
|
13
|
-
|
|
11
|
+
async reply(content) {
|
|
12
|
+
const data = await this.client.api.request(
|
|
14
13
|
"POST",
|
|
15
14
|
`/channels/${this.channelId}/messages`,
|
|
16
15
|
{
|
|
17
16
|
content: content
|
|
18
17
|
}
|
|
19
18
|
)
|
|
19
|
+
|
|
20
|
+
if (!data || !data.id) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
"Discord did not return a valid message: " +
|
|
23
|
+
JSON.stringify(data)
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return new Message(this.client, data)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async edit(content) {
|
|
31
|
+
const data = await this.client.api.request(
|
|
32
|
+
"PATCH",
|
|
33
|
+
`/channels/${this.channelId}/messages/${this.id}`,
|
|
34
|
+
{
|
|
35
|
+
content: content
|
|
36
|
+
}
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
this.content = data.content || content
|
|
40
|
+
|
|
41
|
+
return this
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async delete() {
|
|
45
|
+
await this.client.api.request(
|
|
46
|
+
"DELETE",
|
|
47
|
+
`/channels/${this.channelId}/messages/${this.id}`
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
return true
|
|
20
51
|
}
|
|
21
52
|
}
|
|
22
53
|
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
class SelectMenuBuilder {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.data = {
|
|
4
|
+
type: 3,
|
|
5
|
+
options: []
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
setCustomId(customId) {
|
|
10
|
+
this.data.custom_id = customId
|
|
11
|
+
return this
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
setPlaceholder(placeholder) {
|
|
15
|
+
this.data.placeholder = placeholder
|
|
16
|
+
return this
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
addOptions(...options) {
|
|
20
|
+
for (const option of options) {
|
|
21
|
+
if (!option || !option.label || !option.value) {
|
|
22
|
+
continue
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const data = {
|
|
26
|
+
label: option.label,
|
|
27
|
+
value: option.value
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (option.description) {
|
|
31
|
+
data.description = option.description
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (option.emoji) {
|
|
35
|
+
data.emoji = option.emoji
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (option.default) {
|
|
39
|
+
data.default = true
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.data.options.push(data)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return this
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
setMinValues(min) {
|
|
49
|
+
this.data.min_values = min
|
|
50
|
+
return this
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
setMaxValues(max) {
|
|
54
|
+
this.data.max_values = max
|
|
55
|
+
return this
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
setDisabled(disabled = true) {
|
|
59
|
+
this.data.disabled = disabled
|
|
60
|
+
return this
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
toJSON() {
|
|
64
|
+
return this.data
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
module.exports = SelectMenuBuilder
|