nv-kit 1.0.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 +0 -0
- package/package.json +16 -0
- package/src/command-handler/ChannelCommands.js +52 -0
- package/src/command-handler/Command.js +21 -0
- package/src/command-handler/CommandHandler.js +219 -0
- package/src/command-handler/CustomCommands.js +74 -0
- package/src/command-handler/DisabledCommands.js +50 -0
- package/src/command-handler/PrefixHandler.js +50 -0
- package/src/command-handler/SlashCommands.js +111 -0
- package/src/command-handler/commands/channelcommand.js +69 -0
- package/src/command-handler/commands/customcommand.js +28 -0
- package/src/command-handler/commands/delcustomcmd.js +21 -0
- package/src/command-handler/commands/prefix.js +21 -0
- package/src/command-handler/commands/requiredpermissions.js +110 -0
- package/src/command-handler/commands/requiredroles.js +112 -0
- package/src/command-handler/commands/togglecommand.js +42 -0
- package/src/command-handler/validations/run-time/argument-count.js +24 -0
- package/src/command-handler/validations/run-time/channel-command.js +26 -0
- package/src/command-handler/validations/run-time/disabled-commands.js +21 -0
- package/src/command-handler/validations/run-time/guild-only.js +15 -0
- package/src/command-handler/validations/run-time/has-permissions.js +50 -0
- package/src/command-handler/validations/run-time/has-roles.js +43 -0
- package/src/command-handler/validations/run-time/owner-only.js +12 -0
- package/src/command-handler/validations/run-time/test-only.js +10 -0
- package/src/command-handler/validations/runtime/argument-count.js +24 -0
- package/src/command-handler/validations/runtime/channel-command.js +26 -0
- package/src/command-handler/validations/runtime/disabled-commands.js +21 -0
- package/src/command-handler/validations/runtime/guild-only.js +15 -0
- package/src/command-handler/validations/runtime/has-permissions.js +50 -0
- package/src/command-handler/validations/runtime/has-roles.js +43 -0
- package/src/command-handler/validations/runtime/owner-only.js +12 -0
- package/src/command-handler/validations/runtime/test-only.js +10 -0
- package/src/command-handler/validations/syntax/bad-cooldown-types.js +28 -0
- package/src/command-handler/validations/syntax/callback-required.js +9 -0
- package/src/command-handler/validations/syntax/defer-reply.js +14 -0
- package/src/command-handler/validations/syntax/desc-required-for-slash.js +11 -0
- package/src/command-handler/validations/syntax/owner-only-without-owners.js +11 -0
- package/src/command-handler/validations/syntax/permissions-without-guild-only.js +10 -0
- package/src/command-handler/validations/syntax/test-without-server.js +11 -0
- package/src/event-handler/EventHandler.js +87 -0
- package/src/event-handler/events/interactionCreate/isButton/test.js +3 -0
- package/src/event-handler/events/interactionCreate/isCommand/slash-commands.js +77 -0
- package/src/event-handler/events/messageCreate/isHuman/legacy-commands.js +36 -0
- package/src/index.js +90 -0
- package/src/models/channel-commands-schema.js +16 -0
- package/src/models/cooldown-schema.js +16 -0
- package/src/models/custom-command-schema.js +16 -0
- package/src/models/disabled-commands-schema.js +12 -0
- package/src/models/guild-prefix-schema.js +16 -0
- package/src/models/required-permissions-schema.js +16 -0
- package/src/models/required-roles-schema.js +16 -0
- package/src/util/Cooldowns.js +232 -0
- package/src/util/FeatureHandler.js +20 -0
- package/src/util/get-all-files.js +28 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
const cooldownSchema = require('../models/cooldown-schema')
|
|
2
|
+
|
|
3
|
+
const cooldownDurations = {
|
|
4
|
+
s: 1,
|
|
5
|
+
m: 60,
|
|
6
|
+
h: 60 * 60,
|
|
7
|
+
d: 60 * 60 * 24,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const cooldownTypes = ['perUser', 'perUserPerGuild', 'perGuild', 'global']
|
|
11
|
+
|
|
12
|
+
class Cooldowns {
|
|
13
|
+
// perUser:
|
|
14
|
+
// <`${userId}-${actionId}`: expires>
|
|
15
|
+
// perUsePerGuild:
|
|
16
|
+
// <`${userId}-${guildId}-${actionId}`: expires>
|
|
17
|
+
// perGuild:
|
|
18
|
+
// <`${guildId}-${actionId}`: expires>
|
|
19
|
+
// global:
|
|
20
|
+
// <action: expires>
|
|
21
|
+
_cooldowns = new Map()
|
|
22
|
+
|
|
23
|
+
constructor({
|
|
24
|
+
instance,
|
|
25
|
+
errorMessage = 'Please wait {TIME} before doing that again.',
|
|
26
|
+
botOwnersBypass = false,
|
|
27
|
+
dbRequired = 300, // 5 minutes
|
|
28
|
+
}) {
|
|
29
|
+
this._instance = instance
|
|
30
|
+
this._errorMessage = errorMessage
|
|
31
|
+
this._botOwnersBypass = botOwnersBypass
|
|
32
|
+
this._dbRequired = dbRequired
|
|
33
|
+
|
|
34
|
+
this.loadCooldowns()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async loadCooldowns() {
|
|
38
|
+
await cooldownSchema.deleteMany({
|
|
39
|
+
expires: { $lt: new Date() },
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const results = await cooldownSchema.find({})
|
|
43
|
+
|
|
44
|
+
for (const result of results) {
|
|
45
|
+
const { _id, expires } = result
|
|
46
|
+
|
|
47
|
+
this._cooldowns.set(_id, expires)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
getKeyFromCooldownUsage(cooldownUsage) {
|
|
52
|
+
const { cooldownType, userId, actionId, guildId } = cooldownUsage
|
|
53
|
+
|
|
54
|
+
return this.getKey(cooldownType, userId, actionId, guildId)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async cancelCooldown(cooldownUsage) {
|
|
58
|
+
const key = this.getKeyFromCooldownUsage(cooldownUsage)
|
|
59
|
+
|
|
60
|
+
this._cooldowns.delete(key)
|
|
61
|
+
|
|
62
|
+
await cooldownSchema.deleteOne({ _id: key })
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async updateCooldown(cooldownUsage, expires) {
|
|
66
|
+
const key = this.getKeyFromCooldownUsage(cooldownUsage)
|
|
67
|
+
|
|
68
|
+
this._cooldowns.set(key, expires)
|
|
69
|
+
|
|
70
|
+
const now = new Date()
|
|
71
|
+
const secondsDiff = (expires.getTime() - now.getTime()) / 1000
|
|
72
|
+
|
|
73
|
+
if (secondsDiff > this._dbRequired) {
|
|
74
|
+
await cooldownSchema.findOneAndUpdate(
|
|
75
|
+
{
|
|
76
|
+
_id: key,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
_id: key,
|
|
80
|
+
expires,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
upsert: true,
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
verifyCooldown(duration) {
|
|
90
|
+
if (typeof duration === 'number') {
|
|
91
|
+
return duration
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const split = duration.split(' ')
|
|
95
|
+
|
|
96
|
+
if (split.length !== 2) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
`Duration "${duration}" is an invalid duration. Please use "10 m", "15 s" etc.`
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const quantity = +split[0]
|
|
103
|
+
const type = split[1].toLowerCase()
|
|
104
|
+
|
|
105
|
+
if (!cooldownDurations[type]) {
|
|
106
|
+
throw new Error(
|
|
107
|
+
`Unknown duration type "${type}". Please use one of the following: ${Object.keys(
|
|
108
|
+
cooldownDurations
|
|
109
|
+
)}`
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (quantity <= 0) {
|
|
114
|
+
throw new Error(
|
|
115
|
+
`Invalid quantity of "${quantity}". Please use a value greater than 0.`
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return quantity * cooldownDurations[type]
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
getKey(cooldownType, userId, actionId, guildId) {
|
|
123
|
+
const isPerUser = cooldownType === cooldownTypes[0]
|
|
124
|
+
const isPerUserPerGuild = cooldownType === cooldownTypes[1]
|
|
125
|
+
const isPerGuild = cooldownType === cooldownTypes[2]
|
|
126
|
+
const isGlobal = cooldownType === cooldownTypes[3]
|
|
127
|
+
|
|
128
|
+
if ((isPerUserPerGuild || isPerGuild) && !guildId) {
|
|
129
|
+
throw new Error(
|
|
130
|
+
`Invalid cooldown type "${cooldownType}" used outside of a guild.`
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (isPerUser) {
|
|
135
|
+
return `${userId}-${actionId}`
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (isPerUserPerGuild) {
|
|
139
|
+
return `${userId}-${guildId}-${actionId}`
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (isPerGuild) {
|
|
143
|
+
return `${guildId}-${actionId}`
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (isGlobal) {
|
|
147
|
+
return actionId
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
canBypass(userId) {
|
|
152
|
+
return this._botOwnersBypass && this._instance.botOwners.includes(userId)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async start({ cooldownType, userId, actionId, guildId = '', duration }) {
|
|
156
|
+
if (this.canBypass(userId)) {
|
|
157
|
+
return
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!cooldownTypes.includes(cooldownType)) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
`Invalid cooldown type "${cooldownType}". Please use one of the following: ${cooldownTypes}`
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const seconds = this.verifyCooldown(duration)
|
|
167
|
+
|
|
168
|
+
const key = this.getKey(cooldownType, userId, actionId, guildId)
|
|
169
|
+
|
|
170
|
+
const expires = new Date()
|
|
171
|
+
expires.setSeconds(expires.getSeconds() + seconds)
|
|
172
|
+
|
|
173
|
+
if (seconds >= this._dbRequired) {
|
|
174
|
+
await cooldownSchema.findOneAndUpdate(
|
|
175
|
+
{
|
|
176
|
+
_id: key,
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
_id: key,
|
|
180
|
+
expires,
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
upsert: true,
|
|
184
|
+
}
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
this._cooldowns.set(key, expires)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
canRunAction({
|
|
192
|
+
cooldownType,
|
|
193
|
+
userId,
|
|
194
|
+
actionId,
|
|
195
|
+
guildId = '',
|
|
196
|
+
errorMessage = this._errorMessage,
|
|
197
|
+
}) {
|
|
198
|
+
if (this.canBypass(userId)) {
|
|
199
|
+
return true
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const key = this.getKey(cooldownType, userId, actionId, guildId)
|
|
203
|
+
const expires = this._cooldowns.get(key)
|
|
204
|
+
|
|
205
|
+
if (!expires) {
|
|
206
|
+
return true
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const now = new Date()
|
|
210
|
+
if (now > expires) {
|
|
211
|
+
this._cooldowns.delete(key)
|
|
212
|
+
return true
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const secondsDiff = (expires.getTime() - now.getTime()) / 1000
|
|
216
|
+
const d = Math.floor(secondsDiff / (3600 * 24))
|
|
217
|
+
const h = Math.floor((secondsDiff % (3600 * 24)) / 3600)
|
|
218
|
+
const m = Math.floor((secondsDiff % 3600) / 60)
|
|
219
|
+
const s = Math.floor(secondsDiff % 60)
|
|
220
|
+
|
|
221
|
+
let time = ''
|
|
222
|
+
if (d > 0) time += `${d}d `
|
|
223
|
+
if (h > 0) time += `${h}h `
|
|
224
|
+
if (m > 0) time += `${m}m `
|
|
225
|
+
time += `${s}s`
|
|
226
|
+
|
|
227
|
+
return errorMessage.replace('{TIME}', time)
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
module.exports = Cooldowns
|
|
232
|
+
module.exports.cooldownTypes = cooldownTypes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const getAllFiles = require('./get-all-files')
|
|
2
|
+
|
|
3
|
+
class FeatureHandler {
|
|
4
|
+
constructor(instance, featuresDir, client) {
|
|
5
|
+
this.readFiles(instance, featuresDir, client)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
async readFiles(instance, featuresDir, client) {
|
|
9
|
+
const files = getAllFiles(featuresDir)
|
|
10
|
+
|
|
11
|
+
for (const file of files) {
|
|
12
|
+
const func = require(file)
|
|
13
|
+
if (func instanceof Function) {
|
|
14
|
+
await func(instance, client)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = FeatureHandler
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const p = require('path')
|
|
3
|
+
|
|
4
|
+
const getAllFiles = (path, foldersOnly = false) => {
|
|
5
|
+
const files = fs.readdirSync(path, {
|
|
6
|
+
withFileTypes: true,
|
|
7
|
+
})
|
|
8
|
+
let filesFound = []
|
|
9
|
+
|
|
10
|
+
for (const file of files) {
|
|
11
|
+
const fileName = p.join(path, file.name)
|
|
12
|
+
|
|
13
|
+
if (file.isDirectory()) {
|
|
14
|
+
if (foldersOnly) {
|
|
15
|
+
filesFound.push(fileName)
|
|
16
|
+
} else {
|
|
17
|
+
filesFound = [...filesFound, ...getAllFiles(fileName)]
|
|
18
|
+
}
|
|
19
|
+
continue
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
filesFound.push(fileName)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return filesFound
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = getAllFiles
|