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.
Files changed (54) hide show
  1. package/README.md +0 -0
  2. package/package.json +16 -0
  3. package/src/command-handler/ChannelCommands.js +52 -0
  4. package/src/command-handler/Command.js +21 -0
  5. package/src/command-handler/CommandHandler.js +219 -0
  6. package/src/command-handler/CustomCommands.js +74 -0
  7. package/src/command-handler/DisabledCommands.js +50 -0
  8. package/src/command-handler/PrefixHandler.js +50 -0
  9. package/src/command-handler/SlashCommands.js +111 -0
  10. package/src/command-handler/commands/channelcommand.js +69 -0
  11. package/src/command-handler/commands/customcommand.js +28 -0
  12. package/src/command-handler/commands/delcustomcmd.js +21 -0
  13. package/src/command-handler/commands/prefix.js +21 -0
  14. package/src/command-handler/commands/requiredpermissions.js +110 -0
  15. package/src/command-handler/commands/requiredroles.js +112 -0
  16. package/src/command-handler/commands/togglecommand.js +42 -0
  17. package/src/command-handler/validations/run-time/argument-count.js +24 -0
  18. package/src/command-handler/validations/run-time/channel-command.js +26 -0
  19. package/src/command-handler/validations/run-time/disabled-commands.js +21 -0
  20. package/src/command-handler/validations/run-time/guild-only.js +15 -0
  21. package/src/command-handler/validations/run-time/has-permissions.js +50 -0
  22. package/src/command-handler/validations/run-time/has-roles.js +43 -0
  23. package/src/command-handler/validations/run-time/owner-only.js +12 -0
  24. package/src/command-handler/validations/run-time/test-only.js +10 -0
  25. package/src/command-handler/validations/runtime/argument-count.js +24 -0
  26. package/src/command-handler/validations/runtime/channel-command.js +26 -0
  27. package/src/command-handler/validations/runtime/disabled-commands.js +21 -0
  28. package/src/command-handler/validations/runtime/guild-only.js +15 -0
  29. package/src/command-handler/validations/runtime/has-permissions.js +50 -0
  30. package/src/command-handler/validations/runtime/has-roles.js +43 -0
  31. package/src/command-handler/validations/runtime/owner-only.js +12 -0
  32. package/src/command-handler/validations/runtime/test-only.js +10 -0
  33. package/src/command-handler/validations/syntax/bad-cooldown-types.js +28 -0
  34. package/src/command-handler/validations/syntax/callback-required.js +9 -0
  35. package/src/command-handler/validations/syntax/defer-reply.js +14 -0
  36. package/src/command-handler/validations/syntax/desc-required-for-slash.js +11 -0
  37. package/src/command-handler/validations/syntax/owner-only-without-owners.js +11 -0
  38. package/src/command-handler/validations/syntax/permissions-without-guild-only.js +10 -0
  39. package/src/command-handler/validations/syntax/test-without-server.js +11 -0
  40. package/src/event-handler/EventHandler.js +87 -0
  41. package/src/event-handler/events/interactionCreate/isButton/test.js +3 -0
  42. package/src/event-handler/events/interactionCreate/isCommand/slash-commands.js +77 -0
  43. package/src/event-handler/events/messageCreate/isHuman/legacy-commands.js +36 -0
  44. package/src/index.js +90 -0
  45. package/src/models/channel-commands-schema.js +16 -0
  46. package/src/models/cooldown-schema.js +16 -0
  47. package/src/models/custom-command-schema.js +16 -0
  48. package/src/models/disabled-commands-schema.js +12 -0
  49. package/src/models/guild-prefix-schema.js +16 -0
  50. package/src/models/required-permissions-schema.js +16 -0
  51. package/src/models/required-roles-schema.js +16 -0
  52. package/src/util/Cooldowns.js +232 -0
  53. package/src/util/FeatureHandler.js +20 -0
  54. 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