simple-discord-bot.js 0.1.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/api.js ADDED
@@ -0,0 +1,61 @@
1
+ const https = require("https")
2
+
3
+ class API {
4
+ constructor(token) {
5
+ this.token = token
6
+ }
7
+
8
+ request(method, path, body = null) {
9
+ return new Promise((resolve, reject) => {
10
+ const data = body ? JSON.stringify(body) : null
11
+
12
+ const headers = {
13
+ Authorization: `Bot ${this.token}`,
14
+ "Content-Type": "application/json"
15
+ }
16
+
17
+ if (data) {
18
+ headers["Content-Length"] = Buffer.byteLength(data)
19
+ }
20
+
21
+ const req = https.request({
22
+ hostname: "discord.com",
23
+ path: `/api/v10${path}`,
24
+ method,
25
+ headers
26
+ }, res => {
27
+ let result = ""
28
+
29
+ res.on("data", chunk => {
30
+ result += chunk
31
+ })
32
+
33
+ res.on("end", () => {
34
+ try {
35
+ resolve(JSON.parse(result))
36
+ } catch {
37
+ resolve(result)
38
+ }
39
+ })
40
+ })
41
+
42
+ req.on("error", reject)
43
+
44
+ if (data) {
45
+ req.write(data)
46
+ }
47
+
48
+ req.end()
49
+ })
50
+ }
51
+
52
+ registerCommands(applicationId, commands) {
53
+ return this.request(
54
+ "PUT",
55
+ `/applications/${applicationId}/commands`,
56
+ commands
57
+ )
58
+ }
59
+ }
60
+
61
+ module.exports = API
package/client.js ADDED
@@ -0,0 +1,166 @@
1
+ const EventEmitter = require("events")
2
+ const Gateway = require("./gateway")
3
+ const API = require("./api")
4
+ const Message = require("./structures/Message")
5
+
6
+ const PermissionFlags = {
7
+ CreateInstantInvite: 1n << 0n,
8
+ KickMembers: 1n << 1n,
9
+ BanMembers: 1n << 2n,
10
+ Administrator: 1n << 3n,
11
+ ManageChannels: 1n << 4n,
12
+ ManageGuild: 1n << 5n,
13
+ AddReactions: 1n << 6n,
14
+ ViewAuditLog: 1n << 7n,
15
+ PrioritySpeaker: 1n << 8n,
16
+ Stream: 1n << 9n,
17
+ ViewChannel: 1n << 10n,
18
+ SendMessages: 1n << 11n,
19
+ SendTTSMessages: 1n << 12n,
20
+ ManageMessages: 1n << 13n,
21
+ EmbedLinks: 1n << 14n,
22
+ AttachFiles: 1n << 15n,
23
+ ReadMessageHistory: 1n << 16n,
24
+ MentionEveryone: 1n << 17n,
25
+ UseExternalEmojis: 1n << 18n,
26
+ ViewGuildInsights: 1n << 19n,
27
+ Connect: 1n << 20n,
28
+ Speak: 1n << 21n,
29
+ MuteMembers: 1n << 22n,
30
+ DeafenMembers: 1n << 23n,
31
+ MoveMembers: 1n << 24n,
32
+ UseVAD: 1n << 25n,
33
+ ChangeNickname: 1n << 26n,
34
+ ManageNicknames: 1n << 27n,
35
+ ManageRoles: 1n << 28n,
36
+ ManageWebhooks: 1n << 29n,
37
+ ManageGuildExpressions: 1n << 30n,
38
+ UseApplicationCommands: 1n << 31n
39
+ }
40
+
41
+ class Permissions {
42
+ constructor(value) {
43
+ this.bitfield = BigInt(value || 0)
44
+ }
45
+
46
+ has(permission) {
47
+ const flag = PermissionFlags[permission]
48
+
49
+ if (flag === undefined) {
50
+ return false
51
+ }
52
+
53
+ if ((this.bitfield & PermissionFlags.Administrator) !== 0n) {
54
+ return true
55
+ }
56
+
57
+ return (this.bitfield & flag) !== 0n
58
+ }
59
+ }
60
+
61
+ class Client extends EventEmitter {
62
+ constructor() {
63
+ super()
64
+
65
+ this.token = null
66
+ this.user = null
67
+ this.api = null
68
+ this.gateway = new Gateway(this)
69
+ this.commands = new Map()
70
+ this.stopping = false
71
+
72
+ this.on("rawMessage", data => {
73
+ const message = new Message(this, data)
74
+ this.emit("message", message)
75
+ })
76
+
77
+ this.on("rawInteraction", data => {
78
+ if (data.type !== 2) return
79
+
80
+ const command = this.commands.get(data.data.name)
81
+
82
+ if (!command) return
83
+
84
+ const member = data.member
85
+
86
+ const interaction = {
87
+ id: data.id,
88
+ token: data.token,
89
+
90
+ commandName: data.data.name,
91
+
92
+ user: member?.user || data.user,
93
+
94
+ member: member ? {
95
+ ...member,
96
+
97
+ permissions: new Permissions(member.permissions)
98
+ } : null,
99
+
100
+ channelId: data.channel_id,
101
+
102
+ guildId: data.guild_id || null,
103
+
104
+ options: {},
105
+
106
+ reply: content => {
107
+ return this.api.request(
108
+ "POST",
109
+ `/interactions/${data.id}/${data.token}/callback`,
110
+ {
111
+ type: 4,
112
+ data: {
113
+ content: content
114
+ }
115
+ }
116
+ )
117
+ }
118
+ }
119
+
120
+ for (const option of data.data.options || []) {
121
+ interaction.options[option.name] = option.value
122
+ }
123
+
124
+ command.handler(interaction)
125
+ })
126
+
127
+ process.on("SIGINT", () => {
128
+ if (this.stopping) return
129
+
130
+ this.stopping = true
131
+
132
+ console.log("Stopping bot...")
133
+
134
+ this.destroy()
135
+
136
+ setTimeout(() => {
137
+ process.exit(0)
138
+ }, 1000)
139
+ })
140
+ }
141
+
142
+ login(token) {
143
+ this.token = token
144
+ this.api = new API(token)
145
+
146
+ return this.gateway.connect(token)
147
+ }
148
+
149
+ destroy() {
150
+ this.gateway.destroy()
151
+ this.emit("disconnect")
152
+ }
153
+
154
+ command(name, handler, options = {}) {
155
+ this.commands.set(name, {
156
+ command: {
157
+ name: name,
158
+ description: options.description || "No description",
159
+ options: options.options || []
160
+ },
161
+ handler
162
+ })
163
+ }
164
+ }
165
+
166
+ module.exports = Client
package/gateway.js ADDED
@@ -0,0 +1,91 @@
1
+ const WebSocket = require("ws")
2
+
3
+ class Gateway {
4
+ constructor(client) {
5
+ this.client = client
6
+ this.ws = null
7
+ this.heartbeat = null
8
+ }
9
+
10
+ connect(token) {
11
+ this.ws = new WebSocket(
12
+ "wss://gateway.discord.gg/?v=10&encoding=json"
13
+ )
14
+
15
+ this.ws.on("open", () => {
16
+ this.ws.send(JSON.stringify({
17
+ op: 2,
18
+ d: {
19
+ token: token,
20
+ intents: 33281,
21
+ properties: {
22
+ os: "android",
23
+ browser: "SimpleDiscord.js",
24
+ device: "SimpleDiscord.js"
25
+ }
26
+ }
27
+ }))
28
+ })
29
+
30
+ this.ws.on("message", data => {
31
+ const packet = JSON.parse(data)
32
+
33
+ if (packet.op === 10) {
34
+ this.startHeartbeat(packet.d.heartbeat_interval)
35
+ }
36
+
37
+ if (packet.t === "READY") {
38
+ this.client.user = packet.d.user
39
+ this.client.emit("ready", packet.d)
40
+ }
41
+
42
+ if (packet.t === "MESSAGE_CREATE") {
43
+ this.client.emit("rawMessage", packet.d)
44
+ }
45
+
46
+ if (packet.t === "INTERACTION_CREATE") {
47
+ this.client.emit("rawInteraction", packet.d)
48
+ }
49
+ })
50
+
51
+ this.ws.on("error", error => {
52
+ this.client.emit("error", error)
53
+ })
54
+
55
+ this.ws.on("close", () => {
56
+ this.stopHeartbeat()
57
+ this.ws = null
58
+ this.client.emit("disconnect")
59
+ })
60
+ }
61
+
62
+ startHeartbeat(interval) {
63
+ this.stopHeartbeat()
64
+
65
+ this.heartbeat = setInterval(() => {
66
+ if (!this.ws) return
67
+
68
+ this.ws.send(JSON.stringify({
69
+ op: 1,
70
+ d: null
71
+ }))
72
+ }, interval)
73
+ }
74
+
75
+ stopHeartbeat() {
76
+ if (this.heartbeat) {
77
+ clearInterval(this.heartbeat)
78
+ this.heartbeat = null
79
+ }
80
+ }
81
+
82
+ destroy() {
83
+ this.stopHeartbeat()
84
+
85
+ if (this.ws) {
86
+ this.ws.close(1000, "Bot stopped")
87
+ }
88
+ }
89
+ }
90
+
91
+ module.exports = Gateway
package/index.js ADDED
@@ -0,0 +1,5 @@
1
+ const Client = require("./client")
2
+
3
+ module.exports = {
4
+ Client
5
+ }
package/package.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "simple-discord-bot.js",
3
+ "version": "0.1.0",
4
+ "description": "A simple Discord bot library",
5
+ "main": "index.js",
6
+ "license": "MIT",
7
+ "keywords": [
8
+ "discord",
9
+ "discord-bot",
10
+ "discord-library",
11
+ "discord-api"
12
+ ],
13
+ "dependencies": {
14
+ "ws": "^8.18.3"
15
+ }
16
+ }
@@ -0,0 +1,23 @@
1
+ class Message {
2
+ constructor(client, data) {
3
+ this.client = client
4
+
5
+ this.id = data.id
6
+ this.content = data.content
7
+ this.channelId = data.channel_id
8
+ this.guildId = data.guild_id
9
+ this.author = data.author
10
+ }
11
+
12
+ reply(content) {
13
+ return this.client.api.request(
14
+ "POST",
15
+ `/channels/${this.channelId}/messages`,
16
+ {
17
+ content: content
18
+ }
19
+ )
20
+ }
21
+ }
22
+
23
+ module.exports = Message