@spatulox/simplediscordbot 1.0.30 → 1.0.32
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/.npmignore_old +23 -0
- package/dist/index.d.mts +915 -0
- package/dist/index.d.ts +915 -17
- package/dist/index.js +2576 -36
- package/dist/index.mjs +2554 -0
- package/package.json +3 -2
- package/dist/SimpleDiscordBotInfo.d.ts +0 -8
- package/dist/SimpleDiscordBotInfo.js +0 -14
- package/dist/bot/Bot.d.ts +0 -35
- package/dist/bot/Bot.js +0 -92
- package/dist/bot/BotEnv.d.ts +0 -6
- package/dist/bot/BotEnv.js +0 -24
- package/dist/bot/BotInteraction.d.ts +0 -21
- package/dist/bot/BotInteraction.js +0 -74
- package/dist/bot/BotLog.d.ts +0 -52
- package/dist/bot/BotLog.js +0 -134
- package/dist/bot/BotMessage.d.ts +0 -20
- package/dist/bot/BotMessage.js +0 -110
- package/dist/manager/FileManager.d.ts +0 -37
- package/dist/manager/FileManager.js +0 -136
- package/dist/manager/builder/SendableComponentBuilder.d.ts +0 -3
- package/dist/manager/builder/SendableComponentBuilder.js +0 -63
- package/dist/manager/direct/BasicUserManager.d.ts +0 -28
- package/dist/manager/direct/BasicUserManager.js +0 -81
- package/dist/manager/direct/UserManager.d.ts +0 -6
- package/dist/manager/direct/UserManager.js +0 -18
- package/dist/manager/guild/ChannelManager/ForumChannelManager.d.ts +0 -9
- package/dist/manager/guild/ChannelManager/ForumChannelManager.js +0 -33
- package/dist/manager/guild/ChannelManager/GuildChannelList.d.ts +0 -17
- package/dist/manager/guild/ChannelManager/GuildChannelList.js +0 -20
- package/dist/manager/guild/ChannelManager/GuildChannelManager.d.ts +0 -18
- package/dist/manager/guild/ChannelManager/GuildChannelManager.js +0 -91
- package/dist/manager/guild/ChannelManager/GuildMessageManager.d.ts +0 -23
- package/dist/manager/guild/ChannelManager/GuildMessageManager.js +0 -93
- package/dist/manager/guild/ChannelManager/GuildTextChannelManager.d.ts +0 -9
- package/dist/manager/guild/ChannelManager/GuildTextChannelManager.js +0 -33
- package/dist/manager/guild/ChannelManager/GuildVoiceChannelManager.d.ts +0 -9
- package/dist/manager/guild/ChannelManager/GuildVoiceChannelManager.js +0 -33
- package/dist/manager/guild/ChannelManager/NewsChannelManager.d.ts +0 -9
- package/dist/manager/guild/ChannelManager/NewsChannelManager.js +0 -33
- package/dist/manager/guild/ChannelManager/StageChannelManager.d.ts +0 -9
- package/dist/manager/guild/ChannelManager/StageChannelManager.js +0 -33
- package/dist/manager/guild/ChannelManager/ThreadChannelManager.d.ts +0 -13
- package/dist/manager/guild/ChannelManager/ThreadChannelManager.js +0 -49
- package/dist/manager/guild/GuildManager.d.ts +0 -32
- package/dist/manager/guild/GuildManager.js +0 -144
- package/dist/manager/guild/GuildUserManager.d.ts +0 -49
- package/dist/manager/guild/GuildUserManager.js +0 -251
- package/dist/manager/guild/InviteManager.d.ts +0 -21
- package/dist/manager/guild/InviteManager.js +0 -68
- package/dist/manager/guild/InviteManager_old.d.ts +0 -24
- package/dist/manager/guild/InviteManager_old.js +0 -89
- package/dist/manager/guild/RoleManager.d.ts +0 -24
- package/dist/manager/guild/RoleManager.js +0 -83
- package/dist/manager/interactions/ModalManager.d.ts +0 -23
- package/dist/manager/interactions/ModalManager.js +0 -113
- package/dist/manager/interactions/SelectMenuManager.d.ts +0 -58
- package/dist/manager/interactions/SelectMenuManager.js +0 -123
- package/dist/manager/messages/EmbedManager.d.ts +0 -97
- package/dist/manager/messages/EmbedManager.js +0 -161
- package/dist/manager/messages/ReactionManager.d.ts +0 -26
- package/dist/manager/messages/ReactionManager.js +0 -99
- package/dist/manager/messages/WebhookManager.d.ts +0 -33
- package/dist/manager/messages/WebhookManager.js +0 -108
- package/dist/test/client.d.ts +0 -3
- package/dist/test/client.js +0 -15
- package/dist/test/index.d.ts +0 -2
- package/dist/test/index.js +0 -31
- package/dist/test/randomActivityList.d.ts +0 -3
- package/dist/test/randomActivityList.js +0 -9
- package/dist/type/FolderName.d.ts +0 -2
- package/dist/type/FolderName.js +0 -10
- package/dist/utils/DiscordRegex.d.ts +0 -66
- package/dist/utils/DiscordRegex.js +0 -117
- package/dist/utils/Log.d.ts +0 -9
- package/dist/utils/Log.js +0 -28
- package/dist/utils/SimpleMutex.d.ts +0 -16
- package/dist/utils/SimpleMutex.js +0 -39
- package/dist/utils/network/InternetChecker.d.ts +0 -10
- package/dist/utils/network/InternetChecker.js +0 -54
- package/dist/utils/times/UnitTime.d.ts +0 -187
- package/dist/utils/times/UnitTime.js +0 -85
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2554 @@
|
|
|
1
|
+
// src/bot/Bot.ts
|
|
2
|
+
import { Events, version } from "discord.js";
|
|
3
|
+
|
|
4
|
+
// src/utils/times/UnitTime.ts
|
|
5
|
+
var UnitTime = class {
|
|
6
|
+
constructor(val) {
|
|
7
|
+
this.val = val;
|
|
8
|
+
}
|
|
9
|
+
toMilliseconds() {
|
|
10
|
+
return this.val;
|
|
11
|
+
}
|
|
12
|
+
toSeconds() {
|
|
13
|
+
return this.val / 1e3;
|
|
14
|
+
}
|
|
15
|
+
toMinutes() {
|
|
16
|
+
return this.val / (60 * 1e3);
|
|
17
|
+
}
|
|
18
|
+
toHours() {
|
|
19
|
+
return this.val / (60 * 60 * 1e3);
|
|
20
|
+
}
|
|
21
|
+
toDays() {
|
|
22
|
+
return this.val / (24 * 60 * 60 * 1e3);
|
|
23
|
+
}
|
|
24
|
+
toString() {
|
|
25
|
+
return this.val.toString();
|
|
26
|
+
}
|
|
27
|
+
valueOf() {
|
|
28
|
+
return this.val;
|
|
29
|
+
}
|
|
30
|
+
value() {
|
|
31
|
+
return this.val;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
var Milliseconds = {
|
|
35
|
+
MS_100: new UnitTime(100),
|
|
36
|
+
MS_200: new UnitTime(200),
|
|
37
|
+
MS_500: new UnitTime(500),
|
|
38
|
+
MS_800: new UnitTime(800),
|
|
39
|
+
MS_1000: new UnitTime(1e3)
|
|
40
|
+
};
|
|
41
|
+
var Seconds = {
|
|
42
|
+
SEC_01: new UnitTime(1e3),
|
|
43
|
+
SEC_02: new UnitTime(2e3),
|
|
44
|
+
SEC_03: new UnitTime(3e3),
|
|
45
|
+
SEC_04: new UnitTime(4e3),
|
|
46
|
+
SEC_05: new UnitTime(5e3),
|
|
47
|
+
SEC_06: new UnitTime(6e3),
|
|
48
|
+
SEC_07: new UnitTime(7e3),
|
|
49
|
+
SEC_08: new UnitTime(8e3),
|
|
50
|
+
SEC_09: new UnitTime(9e3),
|
|
51
|
+
SEC_10: new UnitTime(1e4),
|
|
52
|
+
SEC_11: new UnitTime(11e3),
|
|
53
|
+
SEC_12: new UnitTime(12e3),
|
|
54
|
+
SEC_13: new UnitTime(13e3),
|
|
55
|
+
SEC_14: new UnitTime(14e3),
|
|
56
|
+
SEC_15: new UnitTime(15e3),
|
|
57
|
+
SEC_16: new UnitTime(16e3),
|
|
58
|
+
SEC_17: new UnitTime(17e3),
|
|
59
|
+
SEC_18: new UnitTime(18e3),
|
|
60
|
+
SEC_19: new UnitTime(19e3),
|
|
61
|
+
SEC_20: new UnitTime(2e4),
|
|
62
|
+
SEC_21: new UnitTime(21e3),
|
|
63
|
+
SEC_22: new UnitTime(22e3),
|
|
64
|
+
SEC_23: new UnitTime(23e3),
|
|
65
|
+
SEC_24: new UnitTime(24e3),
|
|
66
|
+
SEC_25: new UnitTime(25e3),
|
|
67
|
+
SEC_26: new UnitTime(26e3),
|
|
68
|
+
SEC_27: new UnitTime(27e3),
|
|
69
|
+
SEC_28: new UnitTime(28e3),
|
|
70
|
+
SEC_29: new UnitTime(29e3),
|
|
71
|
+
SEC_30: new UnitTime(3e4),
|
|
72
|
+
SEC_31: new UnitTime(31e3),
|
|
73
|
+
SEC_32: new UnitTime(32e3),
|
|
74
|
+
SEC_33: new UnitTime(33e3),
|
|
75
|
+
SEC_34: new UnitTime(34e3),
|
|
76
|
+
SEC_35: new UnitTime(35e3),
|
|
77
|
+
SEC_36: new UnitTime(36e3),
|
|
78
|
+
SEC_37: new UnitTime(37e3),
|
|
79
|
+
SEC_38: new UnitTime(38e3),
|
|
80
|
+
SEC_39: new UnitTime(39e3),
|
|
81
|
+
SEC_40: new UnitTime(4e4),
|
|
82
|
+
SEC_41: new UnitTime(41e3),
|
|
83
|
+
SEC_42: new UnitTime(42e3),
|
|
84
|
+
SEC_43: new UnitTime(43e3),
|
|
85
|
+
SEC_44: new UnitTime(44e3),
|
|
86
|
+
SEC_45: new UnitTime(45e3),
|
|
87
|
+
SEC_46: new UnitTime(46e3),
|
|
88
|
+
SEC_47: new UnitTime(47e3),
|
|
89
|
+
SEC_48: new UnitTime(48e3),
|
|
90
|
+
SEC_49: new UnitTime(49e3),
|
|
91
|
+
SEC_50: new UnitTime(5e4),
|
|
92
|
+
SEC_51: new UnitTime(51e3),
|
|
93
|
+
SEC_52: new UnitTime(52e3),
|
|
94
|
+
SEC_53: new UnitTime(53e3),
|
|
95
|
+
SEC_54: new UnitTime(54e3),
|
|
96
|
+
SEC_55: new UnitTime(55e3),
|
|
97
|
+
SEC_56: new UnitTime(56e3),
|
|
98
|
+
SEC_57: new UnitTime(57e3),
|
|
99
|
+
SEC_58: new UnitTime(58e3),
|
|
100
|
+
SEC_59: new UnitTime(59e3),
|
|
101
|
+
SEC_60: new UnitTime(6e4)
|
|
102
|
+
};
|
|
103
|
+
var Minutes = {
|
|
104
|
+
MIN_01: new UnitTime(6e4),
|
|
105
|
+
MIN_02: new UnitTime(12e4),
|
|
106
|
+
MIN_03: new UnitTime(18e4),
|
|
107
|
+
MIN_04: new UnitTime(24e4),
|
|
108
|
+
MIN_05: new UnitTime(3e5),
|
|
109
|
+
MIN_06: new UnitTime(36e4),
|
|
110
|
+
MIN_07: new UnitTime(42e4),
|
|
111
|
+
MIN_08: new UnitTime(48e4),
|
|
112
|
+
MIN_09: new UnitTime(54e4),
|
|
113
|
+
MIN_10: new UnitTime(6e5),
|
|
114
|
+
MIN_11: new UnitTime(66e4),
|
|
115
|
+
MIN_12: new UnitTime(72e4),
|
|
116
|
+
MIN_13: new UnitTime(78e4),
|
|
117
|
+
MIN_14: new UnitTime(84e4),
|
|
118
|
+
MIN_15: new UnitTime(9e5),
|
|
119
|
+
MIN_16: new UnitTime(96e4),
|
|
120
|
+
MIN_17: new UnitTime(102e4),
|
|
121
|
+
MIN_18: new UnitTime(108e4),
|
|
122
|
+
MIN_19: new UnitTime(114e4),
|
|
123
|
+
MIN_20: new UnitTime(12e5),
|
|
124
|
+
MIN_21: new UnitTime(126e4),
|
|
125
|
+
MIN_22: new UnitTime(132e4),
|
|
126
|
+
MIN_23: new UnitTime(138e4),
|
|
127
|
+
MIN_24: new UnitTime(144e4),
|
|
128
|
+
MIN_25: new UnitTime(15e5),
|
|
129
|
+
MIN_26: new UnitTime(156e4),
|
|
130
|
+
MIN_27: new UnitTime(162e4),
|
|
131
|
+
MIN_28: new UnitTime(168e4),
|
|
132
|
+
MIN_29: new UnitTime(174e4),
|
|
133
|
+
MIN_30: new UnitTime(18e5),
|
|
134
|
+
MIN_31: new UnitTime(186e4),
|
|
135
|
+
MIN_32: new UnitTime(192e4),
|
|
136
|
+
MIN_33: new UnitTime(198e4),
|
|
137
|
+
MIN_34: new UnitTime(204e4),
|
|
138
|
+
MIN_35: new UnitTime(21e5),
|
|
139
|
+
MIN_36: new UnitTime(216e4),
|
|
140
|
+
MIN_37: new UnitTime(222e4),
|
|
141
|
+
MIN_38: new UnitTime(228e4),
|
|
142
|
+
MIN_39: new UnitTime(234e4),
|
|
143
|
+
MIN_40: new UnitTime(24e5),
|
|
144
|
+
MIN_41: new UnitTime(246e4),
|
|
145
|
+
MIN_42: new UnitTime(252e4),
|
|
146
|
+
MIN_43: new UnitTime(258e4),
|
|
147
|
+
MIN_44: new UnitTime(264e4),
|
|
148
|
+
MIN_45: new UnitTime(27e5),
|
|
149
|
+
MIN_46: new UnitTime(276e4),
|
|
150
|
+
MIN_47: new UnitTime(282e4),
|
|
151
|
+
MIN_48: new UnitTime(288e4),
|
|
152
|
+
MIN_49: new UnitTime(294e4),
|
|
153
|
+
MIN_50: new UnitTime(3e6),
|
|
154
|
+
MIN_51: new UnitTime(306e4),
|
|
155
|
+
MIN_52: new UnitTime(312e4),
|
|
156
|
+
MIN_53: new UnitTime(318e4),
|
|
157
|
+
MIN_54: new UnitTime(324e4),
|
|
158
|
+
MIN_55: new UnitTime(33e5),
|
|
159
|
+
MIN_56: new UnitTime(336e4),
|
|
160
|
+
MIN_57: new UnitTime(342e4),
|
|
161
|
+
MIN_58: new UnitTime(348e4),
|
|
162
|
+
MIN_59: new UnitTime(354e4),
|
|
163
|
+
MIN_60: new UnitTime(36e5)
|
|
164
|
+
};
|
|
165
|
+
var Hours = {
|
|
166
|
+
HOUR_01: new UnitTime(36e5),
|
|
167
|
+
HOUR_02: new UnitTime(72e5),
|
|
168
|
+
HOUR_03: new UnitTime(108e5),
|
|
169
|
+
HOUR_04: new UnitTime(144e5),
|
|
170
|
+
HOUR_05: new UnitTime(18e6),
|
|
171
|
+
HOUR_06: new UnitTime(216e5),
|
|
172
|
+
HOUR_07: new UnitTime(252e5),
|
|
173
|
+
HOUR_08: new UnitTime(288e5),
|
|
174
|
+
HOUR_09: new UnitTime(324e5),
|
|
175
|
+
HOUR_10: new UnitTime(36e6),
|
|
176
|
+
HOUR_11: new UnitTime(396e5),
|
|
177
|
+
HOUR_12: new UnitTime(432e5),
|
|
178
|
+
HOUR_13: new UnitTime(468e5),
|
|
179
|
+
HOUR_14: new UnitTime(504e5),
|
|
180
|
+
HOUR_15: new UnitTime(54e6),
|
|
181
|
+
HOUR_16: new UnitTime(576e5),
|
|
182
|
+
HOUR_17: new UnitTime(612e5),
|
|
183
|
+
HOUR_18: new UnitTime(648e5),
|
|
184
|
+
HOUR_19: new UnitTime(684e5),
|
|
185
|
+
HOUR_20: new UnitTime(72e6),
|
|
186
|
+
HOUR_21: new UnitTime(756e5),
|
|
187
|
+
HOUR_22: new UnitTime(792e5),
|
|
188
|
+
HOUR_23: new UnitTime(828e5),
|
|
189
|
+
HOUR_24: new UnitTime(864e5)
|
|
190
|
+
};
|
|
191
|
+
var Days = {
|
|
192
|
+
DAY_01: new UnitTime(864e5),
|
|
193
|
+
DAY_02: new UnitTime(1728e5),
|
|
194
|
+
DAY_03: new UnitTime(2592e5),
|
|
195
|
+
DAY_04: new UnitTime(3456e5),
|
|
196
|
+
DAY_05: new UnitTime(432e6),
|
|
197
|
+
DAY_06: new UnitTime(5184e5),
|
|
198
|
+
DAY_07: new UnitTime(6048e5),
|
|
199
|
+
DAY_08: new UnitTime(6912e5),
|
|
200
|
+
DAY_09: new UnitTime(7776e5),
|
|
201
|
+
DAY_10: new UnitTime(864e6)
|
|
202
|
+
};
|
|
203
|
+
var Time = {
|
|
204
|
+
milisecond: Milliseconds,
|
|
205
|
+
second: Seconds,
|
|
206
|
+
minute: Minutes,
|
|
207
|
+
hour: Hours,
|
|
208
|
+
day: Days,
|
|
209
|
+
get DAY() {
|
|
210
|
+
const h = (/* @__PURE__ */ new Date()).getHours();
|
|
211
|
+
return h >= 7 && h < 23;
|
|
212
|
+
},
|
|
213
|
+
get NIGHT() {
|
|
214
|
+
return !this.DAY;
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// src/utils/Log.ts
|
|
219
|
+
var Log = class {
|
|
220
|
+
static getPrefix(level) {
|
|
221
|
+
const now = /* @__PURE__ */ new Date();
|
|
222
|
+
const timestamp = `[${now.toLocaleDateString()} - ${now.toLocaleTimeString()}]`;
|
|
223
|
+
return `${timestamp} [${level.toUpperCase()}]`;
|
|
224
|
+
}
|
|
225
|
+
static info(message) {
|
|
226
|
+
console.info(`${this.getPrefix("info")} ${message}`);
|
|
227
|
+
}
|
|
228
|
+
static warn(message) {
|
|
229
|
+
console.warn(`${this.getPrefix("warn")} ${message}`);
|
|
230
|
+
}
|
|
231
|
+
static error(message) {
|
|
232
|
+
console.error(`${this.getPrefix("error")} ${message}`);
|
|
233
|
+
}
|
|
234
|
+
static debug(message) {
|
|
235
|
+
console.debug(`${this.getPrefix("debug")} ${message}`);
|
|
236
|
+
}
|
|
237
|
+
static table(data) {
|
|
238
|
+
const prefix = this.getPrefix("table");
|
|
239
|
+
console.info(`${prefix} Table output:`);
|
|
240
|
+
console.table(data);
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// src/utils/network/InternetChecker.ts
|
|
245
|
+
var InternetChecker = class {
|
|
246
|
+
/**
|
|
247
|
+
* Check internet connection towards 1.1.1.1 (Cloudflare DNS)
|
|
248
|
+
* @param tries Number of attempts (0 = infini)
|
|
249
|
+
*/
|
|
250
|
+
static async checkConnection(tries = 0) {
|
|
251
|
+
let attempt = 0;
|
|
252
|
+
Log.info(
|
|
253
|
+
tries > 0 ? `HTTP ping ${this.TARGET} (max ${tries} attempts)...` : `HTTP ping ${this.TARGET} (infinite attempts)...`
|
|
254
|
+
);
|
|
255
|
+
while (tries === 0 || attempt < tries) {
|
|
256
|
+
try {
|
|
257
|
+
const controller = new AbortController();
|
|
258
|
+
const timeoutId = setTimeout(() => controller.abort(), 5e3);
|
|
259
|
+
const response = await fetch(this.TARGET, {
|
|
260
|
+
method: "HEAD",
|
|
261
|
+
signal: controller.signal,
|
|
262
|
+
cache: "no-store"
|
|
263
|
+
});
|
|
264
|
+
clearTimeout(timeoutId);
|
|
265
|
+
if (response.ok) {
|
|
266
|
+
const latency = response.headers.get("x-response-time") || "<1ms";
|
|
267
|
+
Log.info(`Internet connection OK (${latency})`);
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
270
|
+
} catch (error) {
|
|
271
|
+
attempt++;
|
|
272
|
+
const errorMsg = error.name === "AbortError" ? "Timeout (5s)" : error.message || "Unknown";
|
|
273
|
+
Log.warn(
|
|
274
|
+
tries > 0 ? `Ping failed (${errorMsg}) - Attempt ${attempt}/${tries}` : `Ping failed (${errorMsg}) - Retrying in ${this.RETRY_TIME.toSeconds()} seconds...`
|
|
275
|
+
);
|
|
276
|
+
try {
|
|
277
|
+
await new Promise((resolve) => setTimeout(resolve, this.RETRY_TIME.toMilliseconds()));
|
|
278
|
+
} catch {
|
|
279
|
+
Log.error("Retry delay failed.");
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
Log.error(`No response from ${this.TARGET} after all attempts.`);
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
InternetChecker.TARGET = "https://1.1.1.1";
|
|
288
|
+
// Cloudflare DNS HTTPS
|
|
289
|
+
InternetChecker.RETRY_TIME = Time.second.SEC_30;
|
|
290
|
+
|
|
291
|
+
// src/bot/BotLog.ts
|
|
292
|
+
import { EmbedBuilder } from "discord.js";
|
|
293
|
+
var _BotLog = class _BotLog {
|
|
294
|
+
constructor() {
|
|
295
|
+
}
|
|
296
|
+
static config() {
|
|
297
|
+
return Bot.config.log;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Initialize Discord logging channels and update Bot.log references
|
|
301
|
+
*/
|
|
302
|
+
static async initDiscordLogging() {
|
|
303
|
+
if (!Bot.client.isReady()) {
|
|
304
|
+
Log.warn("Client not ready for Discord logging init");
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (Bot.config.log?.logChannelId) {
|
|
308
|
+
try {
|
|
309
|
+
const logCh = await Bot.client.channels.fetch(Bot.config.log.logChannelId);
|
|
310
|
+
if (logCh?.isTextBased()) {
|
|
311
|
+
_BotLog.logChannel = logCh;
|
|
312
|
+
} else {
|
|
313
|
+
Log.warn(`\u274C Log channel ${Bot.config.log.logChannelId} invalid`);
|
|
314
|
+
}
|
|
315
|
+
} catch (error) {
|
|
316
|
+
Log.error(`\u274C Log channel fetch failed: ${error}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (Bot.config.log?.errorChannelId) {
|
|
320
|
+
try {
|
|
321
|
+
const errorCh = await Bot.client.channels.fetch(Bot.config.log.errorChannelId);
|
|
322
|
+
if (errorCh?.isTextBased()) {
|
|
323
|
+
_BotLog.errorChannel = errorCh;
|
|
324
|
+
} else {
|
|
325
|
+
Log.warn(`\u274C Error channel ${Bot.config.log.errorChannelId} invalid`);
|
|
326
|
+
}
|
|
327
|
+
} catch (error) {
|
|
328
|
+
Log.error(`\u274C Error channel fetch failed: ${error}`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Send content to specific Discord channel
|
|
334
|
+
*/
|
|
335
|
+
static async _sendToChannel(channel, content, prefix = "info") {
|
|
336
|
+
if (!channel) return;
|
|
337
|
+
let msg;
|
|
338
|
+
try {
|
|
339
|
+
if (content instanceof EmbedBuilder) {
|
|
340
|
+
msg = await channel.send({ embeds: [content] });
|
|
341
|
+
} else {
|
|
342
|
+
const timestamp = `\`${(/* @__PURE__ */ new Date()).toISOString()}\``;
|
|
343
|
+
msg = await channel.send(`${prefix.toUpperCase()} ${timestamp} ${content}`);
|
|
344
|
+
}
|
|
345
|
+
} catch (error) {
|
|
346
|
+
Log.error(`Failed to send to Discord channel: ${error}`);
|
|
347
|
+
}
|
|
348
|
+
return msg;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Send INFO log - TEXT or EMBED ! Respecte config.log.info
|
|
352
|
+
*/
|
|
353
|
+
static async info(content) {
|
|
354
|
+
const logConfig = Bot.config.log;
|
|
355
|
+
if (!logConfig || logConfig.info.console) {
|
|
356
|
+
if (!(content instanceof EmbedBuilder)) {
|
|
357
|
+
Log.info(content);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (logConfig?.info.discord && this.logChannel) {
|
|
361
|
+
return await this._sendToChannel(this.logChannel, content, "info");
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Send ERROR log - TEXT or EMBED ! Respecte config.log.error
|
|
366
|
+
*/
|
|
367
|
+
static async error(content) {
|
|
368
|
+
const logConfig = Bot.config.log;
|
|
369
|
+
if (!logConfig || logConfig.error.console) {
|
|
370
|
+
if (!(content instanceof EmbedBuilder)) {
|
|
371
|
+
Log.error(content);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (logConfig?.error.discord && this.errorChannel) {
|
|
375
|
+
return await this._sendToChannel(this.errorChannel, content, "error");
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Send WARNING log - TEXT or EMBED ! Respecte config.log.warn
|
|
380
|
+
*/
|
|
381
|
+
static async warn(content) {
|
|
382
|
+
const logConfig = Bot.config.log;
|
|
383
|
+
if (!logConfig || logConfig?.warn.console) {
|
|
384
|
+
if (!(content instanceof EmbedBuilder)) {
|
|
385
|
+
Log.warn(content);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
if (logConfig?.warn.discord && this.logChannel) {
|
|
389
|
+
return await this._sendToChannel(this.logChannel, content, "warn");
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Send DEBUG log - TEXT or EMBED ! Respecte config.log.debug
|
|
394
|
+
*/
|
|
395
|
+
static async debug(content) {
|
|
396
|
+
const logConfig = Bot.config.log;
|
|
397
|
+
if (!logConfig || logConfig?.debug.console) {
|
|
398
|
+
if (!(content instanceof EmbedBuilder)) {
|
|
399
|
+
Log.debug(content);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if (logConfig?.debug.discord && this.logChannel) {
|
|
403
|
+
return await this._sendToChannel(this.logChannel, content, "debug");
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
_BotLog.logChannel = null;
|
|
408
|
+
_BotLog.errorChannel = null;
|
|
409
|
+
var BotLog = _BotLog;
|
|
410
|
+
|
|
411
|
+
// src/manager/messages/EmbedManager.ts
|
|
412
|
+
import {
|
|
413
|
+
EmbedBuilder as EmbedBuilder2,
|
|
414
|
+
MessageFlags
|
|
415
|
+
} from "discord.js";
|
|
416
|
+
var EmbedColor = /* @__PURE__ */ ((EmbedColor3) => {
|
|
417
|
+
EmbedColor3[EmbedColor3["error"] = 8912917] = "error";
|
|
418
|
+
EmbedColor3[EmbedColor3["success"] = 65280] = "success";
|
|
419
|
+
EmbedColor3[EmbedColor3["black"] = 0] = "black";
|
|
420
|
+
EmbedColor3[EmbedColor3["white"] = 16777215] = "white";
|
|
421
|
+
EmbedColor3[EmbedColor3["red"] = 16711680] = "red";
|
|
422
|
+
EmbedColor3[EmbedColor3["green"] = 65280] = "green";
|
|
423
|
+
EmbedColor3[EmbedColor3["blue"] = 255] = "blue";
|
|
424
|
+
EmbedColor3[EmbedColor3["yellow"] = 16776960] = "yellow";
|
|
425
|
+
EmbedColor3[EmbedColor3["cyan"] = 65535] = "cyan";
|
|
426
|
+
EmbedColor3[EmbedColor3["magenta"] = 16711935] = "magenta";
|
|
427
|
+
EmbedColor3[EmbedColor3["gray"] = 8421504] = "gray";
|
|
428
|
+
EmbedColor3[EmbedColor3["lightgray"] = 13882323] = "lightgray";
|
|
429
|
+
EmbedColor3[EmbedColor3["darkgray"] = 11119017] = "darkgray";
|
|
430
|
+
EmbedColor3[EmbedColor3["orange"] = 16753920] = "orange";
|
|
431
|
+
EmbedColor3[EmbedColor3["purple"] = 8388736] = "purple";
|
|
432
|
+
EmbedColor3[EmbedColor3["pink"] = 16761035] = "pink";
|
|
433
|
+
EmbedColor3[EmbedColor3["brown"] = 10824234] = "brown";
|
|
434
|
+
EmbedColor3[EmbedColor3["lime"] = 65280] = "lime";
|
|
435
|
+
EmbedColor3[EmbedColor3["navy"] = 128] = "navy";
|
|
436
|
+
EmbedColor3[EmbedColor3["teal"] = 32896] = "teal";
|
|
437
|
+
EmbedColor3[EmbedColor3["olive"] = 8421376] = "olive";
|
|
438
|
+
EmbedColor3[EmbedColor3["gold"] = 16766720] = "gold";
|
|
439
|
+
EmbedColor3[EmbedColor3["silver"] = 12632256] = "silver";
|
|
440
|
+
EmbedColor3[EmbedColor3["coral"] = 16744272] = "coral";
|
|
441
|
+
EmbedColor3[EmbedColor3["salmon"] = 16416882] = "salmon";
|
|
442
|
+
EmbedColor3[EmbedColor3["khaki"] = 15787660] = "khaki";
|
|
443
|
+
EmbedColor3[EmbedColor3["plum"] = 14524637] = "plum";
|
|
444
|
+
EmbedColor3[EmbedColor3["lavender"] = 15132410] = "lavender";
|
|
445
|
+
EmbedColor3[EmbedColor3["beige"] = 16119260] = "beige";
|
|
446
|
+
EmbedColor3[EmbedColor3["mint"] = 10026904] = "mint";
|
|
447
|
+
EmbedColor3[EmbedColor3["peach"] = 16767673] = "peach";
|
|
448
|
+
EmbedColor3[EmbedColor3["chocolate"] = 13789470] = "chocolate";
|
|
449
|
+
EmbedColor3[EmbedColor3["crimson"] = 14423100] = "crimson";
|
|
450
|
+
EmbedColor3[EmbedColor3["youtube"] = 16718362] = "youtube";
|
|
451
|
+
EmbedColor3[EmbedColor3["default"] = 6064856] = "default";
|
|
452
|
+
EmbedColor3[EmbedColor3["minecraft"] = 25600] = "minecraft";
|
|
453
|
+
return EmbedColor3;
|
|
454
|
+
})(EmbedColor || {});
|
|
455
|
+
var EmbedManager = class {
|
|
456
|
+
static get BOT_ICON() {
|
|
457
|
+
return Bot.config.botIconUrl || "";
|
|
458
|
+
}
|
|
459
|
+
static get DEFAULT_COLOR() {
|
|
460
|
+
return Bot.config.defaultEmbedColor || 6064856 /* default */;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Creates base embed - SAME SIMPLE API !
|
|
464
|
+
*/
|
|
465
|
+
static create(color = null) {
|
|
466
|
+
const embed = new EmbedBuilder2().setColor(color ?? this.DEFAULT_COLOR).setTimestamp(/* @__PURE__ */ new Date());
|
|
467
|
+
if (this.BOT_ICON && Bot.config.botName) {
|
|
468
|
+
embed.setFooter({
|
|
469
|
+
text: Bot.config.botName,
|
|
470
|
+
iconURL: this.BOT_ICON
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
return embed;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Creates simple embed with just description
|
|
477
|
+
*/
|
|
478
|
+
static simple(description, color = null) {
|
|
479
|
+
return this.create(color).setTitle("").setDescription(description).setTimestamp(null);
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Creates error embed
|
|
483
|
+
*/
|
|
484
|
+
static error(description) {
|
|
485
|
+
return this.create(8912917 /* error */).setTitle("Something went Wrong").setDescription(description);
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Creates success embed
|
|
489
|
+
*/
|
|
490
|
+
static success(description) {
|
|
491
|
+
return this.create(25600 /* minecraft */).setTitle("Success").setDescription(description);
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Creates success embed
|
|
495
|
+
*/
|
|
496
|
+
static description(description) {
|
|
497
|
+
return this.create(25600 /* minecraft */).setDescription(description);
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Creates debug embed
|
|
501
|
+
*/
|
|
502
|
+
static debug(description) {
|
|
503
|
+
return this.create(65280 /* green */).setTitle("Debug").setDescription(description);
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Defer ephemeral reply
|
|
507
|
+
*/
|
|
508
|
+
static deferEphemeral() {
|
|
509
|
+
return { flags: MessageFlags.Ephemeral };
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Quick field adder
|
|
513
|
+
*/
|
|
514
|
+
static field(embed, name, value, inline = false) {
|
|
515
|
+
return embed.addFields({ name, value, inline });
|
|
516
|
+
}
|
|
517
|
+
static fields(embed, fields) {
|
|
518
|
+
fields.forEach((f) => {
|
|
519
|
+
embed.addFields({ name: f.name, value: f.value, inline: f.inline ?? false });
|
|
520
|
+
});
|
|
521
|
+
return embed;
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Fluent API shortcuts
|
|
525
|
+
*/
|
|
526
|
+
static title(embed, title) {
|
|
527
|
+
return embed.setTitle(title);
|
|
528
|
+
}
|
|
529
|
+
static desc(embed, description) {
|
|
530
|
+
return embed.setDescription(description);
|
|
531
|
+
}
|
|
532
|
+
static thumb(embed, url) {
|
|
533
|
+
return embed.setThumbnail(url);
|
|
534
|
+
}
|
|
535
|
+
static image(embed, url) {
|
|
536
|
+
return embed.setImage(url);
|
|
537
|
+
}
|
|
538
|
+
static footer(embed, text) {
|
|
539
|
+
return embed.setFooter({ text, iconURL: this.BOT_ICON });
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Transform embed into objet for interaction.reply()
|
|
543
|
+
*/
|
|
544
|
+
static toInteraction(embed, ephemeral = false) {
|
|
545
|
+
return {
|
|
546
|
+
embeds: [embed],
|
|
547
|
+
flags: ephemeral ? [MessageFlags.Ephemeral] : void 0
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Transform embed into objet to send a message
|
|
552
|
+
*/
|
|
553
|
+
static toMessage(embed) {
|
|
554
|
+
return {
|
|
555
|
+
embeds: [embed]
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
// src/bot/BotMessage.ts
|
|
561
|
+
import {
|
|
562
|
+
User,
|
|
563
|
+
GuildMember
|
|
564
|
+
} from "discord.js";
|
|
565
|
+
|
|
566
|
+
// src/manager/builder/SendableComponentBuilder.ts
|
|
567
|
+
import {
|
|
568
|
+
ActionRowBuilder,
|
|
569
|
+
EmbedBuilder as EmbedBuilder3,
|
|
570
|
+
MessageFlags as MessageFlags2
|
|
571
|
+
} from "discord.js";
|
|
572
|
+
var SendableComponentBuilder = class {
|
|
573
|
+
static isSendableComponent(thing) {
|
|
574
|
+
return thing instanceof EmbedBuilder3 || thing instanceof ActionRowBuilder;
|
|
575
|
+
}
|
|
576
|
+
static build(base, content, components) {
|
|
577
|
+
if (content) {
|
|
578
|
+
base.content = content;
|
|
579
|
+
}
|
|
580
|
+
const comps = Array.isArray(components) ? components : [components].filter(Boolean);
|
|
581
|
+
for (const comp of comps) {
|
|
582
|
+
if (comp instanceof EmbedBuilder3) {
|
|
583
|
+
base.embeds = base.embeds || [];
|
|
584
|
+
base.embeds.push(comp);
|
|
585
|
+
}
|
|
586
|
+
if (comp instanceof ActionRowBuilder) {
|
|
587
|
+
base.components = base.components || [];
|
|
588
|
+
base.components.push(comp);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return base;
|
|
592
|
+
}
|
|
593
|
+
static buildInteraction(contentOrComponent, component, ephemeral = false) {
|
|
594
|
+
let base = {};
|
|
595
|
+
if (typeof contentOrComponent === "string" && !component) {
|
|
596
|
+
base = this.build(base, contentOrComponent);
|
|
597
|
+
}
|
|
598
|
+
if (typeof contentOrComponent !== "string" && !component) {
|
|
599
|
+
base = this.build(base, null, contentOrComponent);
|
|
600
|
+
}
|
|
601
|
+
if (contentOrComponent && typeof contentOrComponent === "string" && component) {
|
|
602
|
+
base = this.build(base, contentOrComponent, component);
|
|
603
|
+
}
|
|
604
|
+
if (ephemeral) {
|
|
605
|
+
base.flags = [MessageFlags2.Ephemeral];
|
|
606
|
+
}
|
|
607
|
+
return base;
|
|
608
|
+
}
|
|
609
|
+
static buildMessage(contentOrComponent, component) {
|
|
610
|
+
let base = {};
|
|
611
|
+
if (typeof contentOrComponent === "string" && !component) {
|
|
612
|
+
return this.build(base, contentOrComponent);
|
|
613
|
+
}
|
|
614
|
+
if (typeof contentOrComponent !== "string" && !component) {
|
|
615
|
+
return this.build(base, null, contentOrComponent);
|
|
616
|
+
}
|
|
617
|
+
if (typeof contentOrComponent == "string" && component) {
|
|
618
|
+
return this.build(base, contentOrComponent, component);
|
|
619
|
+
}
|
|
620
|
+
throw new Error("At least content or component need to be defined to build a message");
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
// src/bot/BotMessage.ts
|
|
625
|
+
var BotMessage = class {
|
|
626
|
+
static async send(channel, content, component) {
|
|
627
|
+
try {
|
|
628
|
+
if (!channel) {
|
|
629
|
+
Log.warn("Cannot send message: invalid channel");
|
|
630
|
+
return null;
|
|
631
|
+
}
|
|
632
|
+
if (typeof channel === "string") {
|
|
633
|
+
const fetchedChannel = Bot.client.channels.cache.get(channel);
|
|
634
|
+
if (!fetchedChannel?.isTextBased()) {
|
|
635
|
+
Log.warn(`Invalid channel ID: ${channel}`);
|
|
636
|
+
return null;
|
|
637
|
+
}
|
|
638
|
+
channel = fetchedChannel;
|
|
639
|
+
}
|
|
640
|
+
let messageCreate;
|
|
641
|
+
if (typeof content !== "string" && !component) {
|
|
642
|
+
if (SendableComponentBuilder.isSendableComponent(content)) {
|
|
643
|
+
messageCreate = SendableComponentBuilder.buildMessage(content);
|
|
644
|
+
} else {
|
|
645
|
+
messageCreate = content;
|
|
646
|
+
}
|
|
647
|
+
} else {
|
|
648
|
+
content = content;
|
|
649
|
+
if (content && component) {
|
|
650
|
+
messageCreate = SendableComponentBuilder.buildMessage(content, component);
|
|
651
|
+
} else if (content) {
|
|
652
|
+
messageCreate = SendableComponentBuilder.buildMessage(content);
|
|
653
|
+
} else if (component) {
|
|
654
|
+
messageCreate = SendableComponentBuilder.buildMessage(component);
|
|
655
|
+
} else {
|
|
656
|
+
throw new Error("content and component cannot be null at the same time");
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
try {
|
|
660
|
+
return await channel.send(messageCreate);
|
|
661
|
+
} catch (e) {
|
|
662
|
+
throw e;
|
|
663
|
+
}
|
|
664
|
+
} catch (e) {
|
|
665
|
+
Log.error(`Failed to send message : ${e}`);
|
|
666
|
+
return null;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
static async sendDM(user, content, component) {
|
|
670
|
+
try {
|
|
671
|
+
let targetUser;
|
|
672
|
+
if (user instanceof User || user instanceof GuildMember) {
|
|
673
|
+
targetUser = user instanceof GuildMember ? user.user : user;
|
|
674
|
+
} else {
|
|
675
|
+
targetUser = await Bot.client.users.fetch(user);
|
|
676
|
+
}
|
|
677
|
+
let messageCreate;
|
|
678
|
+
if (content && component) {
|
|
679
|
+
messageCreate = SendableComponentBuilder.buildMessage(content, component);
|
|
680
|
+
} else if (content) {
|
|
681
|
+
messageCreate = SendableComponentBuilder.buildMessage(content);
|
|
682
|
+
} else if (component) {
|
|
683
|
+
messageCreate = SendableComponentBuilder.buildMessage(component);
|
|
684
|
+
} else {
|
|
685
|
+
throw new Error("content and component cannot be null at the same time");
|
|
686
|
+
}
|
|
687
|
+
return await targetUser.send(messageCreate);
|
|
688
|
+
} catch (error) {
|
|
689
|
+
Log.error(`Failed to send message to ${user}: ${error}`);
|
|
690
|
+
return null;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* Quick success message
|
|
695
|
+
*/
|
|
696
|
+
static success(channel, message) {
|
|
697
|
+
const embed = EmbedManager.success(message);
|
|
698
|
+
if (channel instanceof User || channel instanceof GuildMember) {
|
|
699
|
+
return this.sendDM(channel, message, embed);
|
|
700
|
+
}
|
|
701
|
+
return this.send(channel, message, embed);
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Quick error message
|
|
705
|
+
*/
|
|
706
|
+
static error(channel, message) {
|
|
707
|
+
const embed = EmbedManager.error(message);
|
|
708
|
+
if (channel instanceof User || channel instanceof GuildMember) {
|
|
709
|
+
return this.sendDM(channel, message, embed);
|
|
710
|
+
}
|
|
711
|
+
return this.send(channel, message, embed);
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
// src/utils/DiscordRegex.ts
|
|
716
|
+
var _DiscordRegex = class _DiscordRegex {
|
|
717
|
+
/**
|
|
718
|
+
* Validate Discord ID Discord (18)
|
|
719
|
+
*/
|
|
720
|
+
static isDiscordId(id) {
|
|
721
|
+
return this.USER_ID.test(id) || this.GUILD_ID.test(id) || this.CHANNEL_ID.test(id);
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* Validate a bot ID (19)
|
|
725
|
+
*/
|
|
726
|
+
static isBotMention(mention) {
|
|
727
|
+
return this.BOT_REGEX.test(mention);
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Validate a User ping
|
|
731
|
+
*/
|
|
732
|
+
static isUserMention(mention) {
|
|
733
|
+
return this.USER_REGEX.test(mention);
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Validate a Discord username
|
|
737
|
+
*/
|
|
738
|
+
static isUsername(username) {
|
|
739
|
+
return this.USERNAME.test(username);
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Type guard for Discord ID
|
|
743
|
+
*/
|
|
744
|
+
static isDiscordIdType(id) {
|
|
745
|
+
return this.isDiscordId(id);
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Any Discord URL
|
|
749
|
+
*/
|
|
750
|
+
static isDiscordUrl(url) {
|
|
751
|
+
return this.URL_REGEX.test(url) || this.INVITE.test(url);
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Any discord mention
|
|
755
|
+
*/
|
|
756
|
+
static isAnyMention(text) {
|
|
757
|
+
return this.DISCORD_MENTION_REGEX.test(text);
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* List all regex
|
|
761
|
+
*/
|
|
762
|
+
static listAll() {
|
|
763
|
+
return {
|
|
764
|
+
SPACE: this.SPACE,
|
|
765
|
+
URL_REGEX: this.URL_REGEX,
|
|
766
|
+
USER_REGEX: this.USER_REGEX,
|
|
767
|
+
BOT_REGEX: this.BOT_REGEX,
|
|
768
|
+
CHANNEL_REGEX: this.CHANNEL_REGEX,
|
|
769
|
+
ROLE_REGEX: this.ROLE_REGEX,
|
|
770
|
+
DISCORD_PING_REGEX: this.DISCORD_PING_REGEX,
|
|
771
|
+
DISCORD_MENTION_REGEX: this.DISCORD_MENTION_REGEX,
|
|
772
|
+
USER_ID: this.USER_ID,
|
|
773
|
+
CHANNEL_ID: this.CHANNEL_ID,
|
|
774
|
+
GUILD_ID: this.GUILD_ID,
|
|
775
|
+
USERNAME: this.USERNAME,
|
|
776
|
+
USERNAME_DISCRIM: this.USERNAME_DISCRIM,
|
|
777
|
+
CHANNEL_MENTION: this.CHANNEL_MENTION,
|
|
778
|
+
USER_MENTION: this.USER_MENTION,
|
|
779
|
+
ROLE_MENTION: this.ROLE_MENTION,
|
|
780
|
+
INVITE: this.INVITE,
|
|
781
|
+
EMOJI: this.EMOJI
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
};
|
|
785
|
+
// Caractères spéciaux
|
|
786
|
+
_DiscordRegex.SPACE = "\u200B";
|
|
787
|
+
// URLs basiques
|
|
788
|
+
_DiscordRegex.URL_REGEX = /(https?:\/\/[^s]+)/;
|
|
789
|
+
/* DISCORD REGEX */
|
|
790
|
+
_DiscordRegex.USER_REGEX = /<@\d{18}>/;
|
|
791
|
+
_DiscordRegex.BOT_REGEX = /<@\d{19}>/;
|
|
792
|
+
_DiscordRegex.CHANNEL_REGEX = /(<#\d{19}>)|(<id:(browse|customize|guide)>)/;
|
|
793
|
+
_DiscordRegex.ROLE_REGEX = /<@&\d{19}>/;
|
|
794
|
+
/**
|
|
795
|
+
* Mention a User
|
|
796
|
+
* Mention a Role
|
|
797
|
+
*/
|
|
798
|
+
_DiscordRegex.DISCORD_PING_REGEX = new RegExp(
|
|
799
|
+
`(${_DiscordRegex.USER_REGEX.source})|(${_DiscordRegex.BOT_REGEX.source})|(${_DiscordRegex.ROLE_REGEX.source})`
|
|
800
|
+
);
|
|
801
|
+
/**
|
|
802
|
+
* Mention a User
|
|
803
|
+
* Mention a Role
|
|
804
|
+
* Mention a Channel
|
|
805
|
+
*/
|
|
806
|
+
_DiscordRegex.DISCORD_MENTION_REGEX = new RegExp(
|
|
807
|
+
`(${_DiscordRegex.DISCORD_PING_REGEX.source})|(${_DiscordRegex.CHANNEL_REGEX.source})`
|
|
808
|
+
);
|
|
809
|
+
// ID Discord (user, channel guild)
|
|
810
|
+
_DiscordRegex.USER_ID = /^[0-9]{18}$/;
|
|
811
|
+
_DiscordRegex.CHANNEL_ID = /^[0-9]{18}$/;
|
|
812
|
+
_DiscordRegex.GUILD_ID = /^[0-9]{19}$/;
|
|
813
|
+
_DiscordRegex.BOT_ID = /^[0-9]{19}$/;
|
|
814
|
+
// Username Discord (2-32 caractères alphanumériques + _ .)
|
|
815
|
+
_DiscordRegex.USERNAME = /^[a-zA-Z0-9_]{2,32}$/;
|
|
816
|
+
// Username + discrim (ancien format)
|
|
817
|
+
_DiscordRegex.USERNAME_DISCRIM = /^[a-zA-Z0-9_]{2,32}#\d{4}$/;
|
|
818
|
+
// Channel mention <#123456789012345678>
|
|
819
|
+
_DiscordRegex.CHANNEL_MENTION = /^<#([0-9]{18})>$/;
|
|
820
|
+
// User mention <@123456789012345678> ou <@!123456789012345678>
|
|
821
|
+
_DiscordRegex.USER_MENTION = /^<@!?([0-9]{18})>$/;
|
|
822
|
+
// Role mention <@&123456789012345678>
|
|
823
|
+
_DiscordRegex.ROLE_MENTION = /^<@&([0-9]{18})>$/;
|
|
824
|
+
// URL Invite Discord
|
|
825
|
+
_DiscordRegex.INVITE = /^discord(?:app\.com\/invite|gg)\/[a-zA-Z0-9]+$/;
|
|
826
|
+
// Emoji Discord (custom or unicode)
|
|
827
|
+
_DiscordRegex.EMOJI = /^<a?:[a-zA-Z0-9_]{2,32}:[0-9]{18}>$|^[\u{1F300}-\u{1F5FF}\u{1F600}-\u{1F64F}\u{1F680}-\u{1F6FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]+$/u;
|
|
828
|
+
var DiscordRegex = _DiscordRegex;
|
|
829
|
+
|
|
830
|
+
// src/bot/BotEnv.ts
|
|
831
|
+
var BotEnv = {
|
|
832
|
+
get token() {
|
|
833
|
+
const token = process.env.DISCORD_BOT_TOKEN;
|
|
834
|
+
if (!token) throw new Error("Missing environment variable : DISCORD_BOT_TOKEN");
|
|
835
|
+
return token;
|
|
836
|
+
},
|
|
837
|
+
get dev() {
|
|
838
|
+
return process.env.DEV === "true";
|
|
839
|
+
},
|
|
840
|
+
get clientId() {
|
|
841
|
+
const token = process.env.DISCORD_BOT_CLIENTID;
|
|
842
|
+
if (!token) throw new Error("Missing environment variable : DISCORD_BOT_CLIENTID");
|
|
843
|
+
if (!DiscordRegex.BOT_ID.test(token)) {
|
|
844
|
+
throw new Error("Invalid token format");
|
|
845
|
+
}
|
|
846
|
+
return token;
|
|
847
|
+
}
|
|
848
|
+
};
|
|
849
|
+
|
|
850
|
+
// src/bot/BotInteraction.ts
|
|
851
|
+
var BotInteraction = class {
|
|
852
|
+
/**
|
|
853
|
+
* InteractionReplyOptions && InteractionUpdateOptions
|
|
854
|
+
* The two have "content", "embeds" & "flags" field, so an internal cast is ok, unless discord/discordjs deprecate it
|
|
855
|
+
*/
|
|
856
|
+
static buildReplyOptions(content, component, ephemeral) {
|
|
857
|
+
return this._buildOptions(content, component, ephemeral);
|
|
858
|
+
}
|
|
859
|
+
static buildUpdateOptions(content, component) {
|
|
860
|
+
return this._buildOptions(content, component, false);
|
|
861
|
+
}
|
|
862
|
+
static _buildOptions(content, component, ephemeral) {
|
|
863
|
+
return SendableComponentBuilder.buildInteraction(content, component, ephemeral);
|
|
864
|
+
}
|
|
865
|
+
static async send(interaction, content, component = false, ephemeral = false) {
|
|
866
|
+
if (!interaction.isRepliable()) return false;
|
|
867
|
+
const options = this.buildReplyOptions(
|
|
868
|
+
typeof content === "string" ? content : "",
|
|
869
|
+
typeof content === "string" ? component : content,
|
|
870
|
+
typeof content === "string" ? ephemeral : component
|
|
871
|
+
);
|
|
872
|
+
if (!interaction.deferred && !interaction.replied) {
|
|
873
|
+
return await interaction.reply(options);
|
|
874
|
+
} else {
|
|
875
|
+
return await interaction.followUp(options);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
static async reply(interaction, content, component = false, ephemeral = false) {
|
|
879
|
+
if (!interaction.isRepliable()) return false;
|
|
880
|
+
const options = this.buildReplyOptions(
|
|
881
|
+
typeof content === "string" ? content : "",
|
|
882
|
+
typeof content === "string" ? component : content,
|
|
883
|
+
typeof content === "string" ? ephemeral : component
|
|
884
|
+
);
|
|
885
|
+
return interaction.reply(options);
|
|
886
|
+
}
|
|
887
|
+
static async followUp(interaction, content, component = false, ephemeral = false) {
|
|
888
|
+
if (!interaction.isRepliable()) return false;
|
|
889
|
+
const options = this.buildReplyOptions(
|
|
890
|
+
typeof content === "string" ? content : "",
|
|
891
|
+
typeof content === "string" ? component : content,
|
|
892
|
+
typeof content === "string" ? ephemeral : component
|
|
893
|
+
);
|
|
894
|
+
return interaction.followUp(options);
|
|
895
|
+
}
|
|
896
|
+
static async defer(interaction) {
|
|
897
|
+
if (!interaction.isRepliable()) return;
|
|
898
|
+
if (interaction.isChatInputCommand() || interaction.isContextMenuCommand()) {
|
|
899
|
+
if (!interaction.deferred && !interaction.replied) {
|
|
900
|
+
await interaction.deferReply();
|
|
901
|
+
}
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
if (interaction.isButton() || interaction.isAnySelectMenu() || interaction.isModalSubmit()) {
|
|
905
|
+
if (!interaction.deferred && !interaction.replied) {
|
|
906
|
+
await interaction.deferUpdate();
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
static async update(interaction, content, component) {
|
|
911
|
+
if (!interaction.isRepliable()) return false;
|
|
912
|
+
const options = this.buildUpdateOptions(
|
|
913
|
+
typeof content === "string" ? content : "",
|
|
914
|
+
typeof content === "string" ? component : content
|
|
915
|
+
);
|
|
916
|
+
if (interaction.isMessageComponent()) {
|
|
917
|
+
return await interaction.update(options);
|
|
918
|
+
}
|
|
919
|
+
if (interaction.deferred || interaction.replied) {
|
|
920
|
+
return await interaction.editReply(options);
|
|
921
|
+
}
|
|
922
|
+
return false;
|
|
923
|
+
}
|
|
924
|
+
};
|
|
925
|
+
|
|
926
|
+
// src/bot/Bot.ts
|
|
927
|
+
var _Bot = class _Bot {
|
|
928
|
+
get config() {
|
|
929
|
+
return _Bot._config;
|
|
930
|
+
}
|
|
931
|
+
get client() {
|
|
932
|
+
return _Bot._client;
|
|
933
|
+
}
|
|
934
|
+
static get client() {
|
|
935
|
+
return _Bot._client;
|
|
936
|
+
}
|
|
937
|
+
static get config() {
|
|
938
|
+
return _Bot._config;
|
|
939
|
+
}
|
|
940
|
+
constructor(client, config) {
|
|
941
|
+
Log.info("----------------------------------------------------");
|
|
942
|
+
Log.info("Starting Bot");
|
|
943
|
+
_Bot.criticConfig = { dev: BotEnv.dev, token: BotEnv.token };
|
|
944
|
+
_Bot._config = { ...config, clientId: BotEnv.clientId };
|
|
945
|
+
_Bot._client = client;
|
|
946
|
+
(async () => {
|
|
947
|
+
Log.info(`Using discord.js version: ${version}`);
|
|
948
|
+
Log.info("Trying to connect to Discord Servers");
|
|
949
|
+
await InternetChecker.checkConnection(3);
|
|
950
|
+
await this.login();
|
|
951
|
+
})();
|
|
952
|
+
}
|
|
953
|
+
async login(maxTries = 3) {
|
|
954
|
+
let success = false;
|
|
955
|
+
let tries = 0;
|
|
956
|
+
while (!success && tries < maxTries) {
|
|
957
|
+
try {
|
|
958
|
+
await _Bot._client.login(_Bot.criticConfig.token);
|
|
959
|
+
success = true;
|
|
960
|
+
_Bot._client.on(Events.ClientReady, async () => {
|
|
961
|
+
if (_Bot._client.user) {
|
|
962
|
+
await _Bot.log.initDiscordLogging();
|
|
963
|
+
Log.info(`Connected on ${_Bot._client.guilds.cache.size} servers as ${_Bot._client.user.tag}`);
|
|
964
|
+
_Bot.log.info(EmbedManager.description("Bot Started"));
|
|
965
|
+
}
|
|
966
|
+
});
|
|
967
|
+
} catch (error) {
|
|
968
|
+
Log.error(`Connection error : ${error}. Trying again...`);
|
|
969
|
+
tries++;
|
|
970
|
+
await new Promise(
|
|
971
|
+
(resolve) => setTimeout(resolve, Time.second.SEC_03.toMilliseconds())
|
|
972
|
+
);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
if (!success) {
|
|
976
|
+
Log.error("Impossible to connect the bot after 3 attempts");
|
|
977
|
+
return false;
|
|
978
|
+
}
|
|
979
|
+
return true;
|
|
980
|
+
}
|
|
981
|
+
static setActivity(message, type) {
|
|
982
|
+
if (_Bot._client.user) {
|
|
983
|
+
_Bot._client.user.setActivity({ name: message, type });
|
|
984
|
+
Log.info(`Activity defined : ${message}`);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
static setRandomActivity(randomActivity, intervalMs = null) {
|
|
988
|
+
if (randomActivity.length == 0) {
|
|
989
|
+
Log.error("Bot.randomActivity = [{}] is empty");
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
992
|
+
const pickRandom = () => {
|
|
993
|
+
const random = randomActivity[Math.floor(Math.random() * randomActivity.length)];
|
|
994
|
+
_Bot.setActivity(random.message, random.type);
|
|
995
|
+
return random;
|
|
996
|
+
};
|
|
997
|
+
if (intervalMs === null) {
|
|
998
|
+
pickRandom();
|
|
999
|
+
Log.info(`Activity set ONCE`);
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
pickRandom();
|
|
1003
|
+
setInterval(async () => {
|
|
1004
|
+
pickRandom();
|
|
1005
|
+
}, intervalMs);
|
|
1006
|
+
Log.info(`Random activity started (every ${Math.round(intervalMs / 6e4)}min)`);
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
1009
|
+
};
|
|
1010
|
+
// Static ref
|
|
1011
|
+
_Bot.log = BotLog;
|
|
1012
|
+
_Bot.message = BotMessage;
|
|
1013
|
+
_Bot.interaction = BotInteraction;
|
|
1014
|
+
var Bot = _Bot;
|
|
1015
|
+
|
|
1016
|
+
// src/manager/FileManager.ts
|
|
1017
|
+
import path from "path";
|
|
1018
|
+
import fs from "fs/promises";
|
|
1019
|
+
var FileManager = class {
|
|
1020
|
+
/**
|
|
1021
|
+
* Reads a JSON file synchronously.
|
|
1022
|
+
* @param filePath Full path to the JSON file
|
|
1023
|
+
* @returns Parsed JSON object or 'Error' string on failure
|
|
1024
|
+
*/
|
|
1025
|
+
static async readJsonFile(filePath) {
|
|
1026
|
+
try {
|
|
1027
|
+
const data = await fs.readFile(filePath, "utf8");
|
|
1028
|
+
return JSON.parse(data);
|
|
1029
|
+
} catch (error) {
|
|
1030
|
+
Log.error(`Failed to read JSON file ${filePath}: ${error}`);
|
|
1031
|
+
return false;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Lists all directories in a given path.
|
|
1036
|
+
* @param directoryPath Path to scan for directories
|
|
1037
|
+
* @returns Array of directory names or false on error
|
|
1038
|
+
*/
|
|
1039
|
+
static async listDirectories(directoryPath) {
|
|
1040
|
+
try {
|
|
1041
|
+
const files = await fs.readdir(directoryPath, { withFileTypes: true });
|
|
1042
|
+
const directories = files.filter((file) => file.isDirectory()).map((dir) => dir.name);
|
|
1043
|
+
return directories;
|
|
1044
|
+
} catch (error) {
|
|
1045
|
+
Log.error(`Failed to read directory ${directoryPath}: ${error}`);
|
|
1046
|
+
return false;
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
/**
|
|
1050
|
+
* Lists all JSON files in a directory.
|
|
1051
|
+
* @param directoryPath Path to scan for JSON files
|
|
1052
|
+
* @returns Array of JSON filenames or false on error
|
|
1053
|
+
*/
|
|
1054
|
+
static async listJsonFiles(directoryPath) {
|
|
1055
|
+
try {
|
|
1056
|
+
const files = await fs.readdir(directoryPath);
|
|
1057
|
+
return files.filter((file) => path.extname(file) === ".json");
|
|
1058
|
+
} catch (error) {
|
|
1059
|
+
Log.error(`Failed to read directory ${directoryPath}: ${error}`);
|
|
1060
|
+
return false;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Lists files with specific extension in a directory.
|
|
1065
|
+
* @param directoryPath Path to scan
|
|
1066
|
+
* @param extension File extension (with or without dot)
|
|
1067
|
+
* @returns Array of matching filenames or 'Error' string on failure
|
|
1068
|
+
*/
|
|
1069
|
+
static async listFiles(directoryPath, extension) {
|
|
1070
|
+
if (typeof directoryPath !== "string" || typeof extension !== "string") {
|
|
1071
|
+
Log.error("Directory path and extension must be strings");
|
|
1072
|
+
return false;
|
|
1073
|
+
}
|
|
1074
|
+
try {
|
|
1075
|
+
let ext = extension;
|
|
1076
|
+
if (ext.startsWith(".")) {
|
|
1077
|
+
ext = ext.slice(1);
|
|
1078
|
+
}
|
|
1079
|
+
const files = await fs.readdir(directoryPath);
|
|
1080
|
+
return files.filter((file) => path.extname(file) === `.${ext}`);
|
|
1081
|
+
} catch (error) {
|
|
1082
|
+
Log.error(`Failed to read directory ${directoryPath}: ${error}`);
|
|
1083
|
+
return false;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Creates directory structure and writes JSON data to file.
|
|
1088
|
+
* @param directoryPath Full directory path (creates if missing)
|
|
1089
|
+
* @param filename Filename without extension
|
|
1090
|
+
* @param data Data to write (JSON serializable)
|
|
1091
|
+
* @param sendErrorToErrorChannel Send error to the error channel
|
|
1092
|
+
* @returns true on success, false on failure
|
|
1093
|
+
*/
|
|
1094
|
+
static async writeJsonFile(directoryPath, filename, data, sendErrorToErrorChannel = true) {
|
|
1095
|
+
if (Array.isArray(data) && data.length === 1 && data[0] === "Error") {
|
|
1096
|
+
Log.error(`Cannot save data for ${filename}: data contains 'Error'`);
|
|
1097
|
+
return false;
|
|
1098
|
+
}
|
|
1099
|
+
try {
|
|
1100
|
+
const directories = directoryPath.split(path.sep).filter(Boolean);
|
|
1101
|
+
let currentPath = "";
|
|
1102
|
+
for (const dir of directories) {
|
|
1103
|
+
currentPath = path.join(currentPath, dir);
|
|
1104
|
+
try {
|
|
1105
|
+
await fs.access(currentPath);
|
|
1106
|
+
} catch {
|
|
1107
|
+
await fs.mkdir(currentPath, { recursive: true });
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
if (!filename || filename.trim() === "") {
|
|
1111
|
+
Log.error("Cannot write JSON file: empty filename");
|
|
1112
|
+
return false;
|
|
1113
|
+
}
|
|
1114
|
+
const cleanFilename = filename.replace(/\.json$/i, "");
|
|
1115
|
+
const filePath = path.join(directoryPath, `${cleanFilename}.json`);
|
|
1116
|
+
const jsonContent = JSON.stringify(data, null, 2);
|
|
1117
|
+
await fs.writeFile(filePath, jsonContent);
|
|
1118
|
+
Log.info(`Successfully wrote data to ${filePath}`);
|
|
1119
|
+
return true;
|
|
1120
|
+
} catch (error) {
|
|
1121
|
+
const cleanFilename = filename.replace(/\.json$/i, "") || "unknown";
|
|
1122
|
+
if (sendErrorToErrorChannel) {
|
|
1123
|
+
await Bot.log.info(EmbedManager.error(`Failed to write file ${directoryPath}/${cleanFilename}.json: ${error}`));
|
|
1124
|
+
} else {
|
|
1125
|
+
Log.error(`Failed to write file ${directoryPath}/${cleanFilename}.json: ${error}`);
|
|
1126
|
+
}
|
|
1127
|
+
return false;
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
};
|
|
1131
|
+
|
|
1132
|
+
// src/manager/messages/WebhookManager.ts
|
|
1133
|
+
import {
|
|
1134
|
+
ThreadChannel as ThreadChannel2
|
|
1135
|
+
} from "discord.js";
|
|
1136
|
+
var WebhookManager = class {
|
|
1137
|
+
constructor(channel, name = Bot.config.botName || "", avatarURL) {
|
|
1138
|
+
this.channel = channel;
|
|
1139
|
+
this.name = name;
|
|
1140
|
+
this.avatarURL = avatarURL;
|
|
1141
|
+
this.webhook = null;
|
|
1142
|
+
}
|
|
1143
|
+
get textChannel() {
|
|
1144
|
+
return this.channel instanceof ThreadChannel2 ? this.channel.parent : this.channel;
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Get or create webhook (lazy initialization)
|
|
1148
|
+
*/
|
|
1149
|
+
async getWebhook() {
|
|
1150
|
+
if (this.webhook) return this.webhook;
|
|
1151
|
+
try {
|
|
1152
|
+
const webhooks = await this.textChannel.fetchWebhooks();
|
|
1153
|
+
this.webhook = webhooks.find((h) => h.name === this.name) ?? await this.textChannel.createWebhook({
|
|
1154
|
+
name: this.name,
|
|
1155
|
+
avatar: this.avatarURL,
|
|
1156
|
+
reason: "Auto-created by WebhookManager"
|
|
1157
|
+
});
|
|
1158
|
+
Log.info(`Webhook ${this.webhook.id} ready for ${this.textChannel.id}`);
|
|
1159
|
+
return this.webhook;
|
|
1160
|
+
} catch (error) {
|
|
1161
|
+
Log.error(`Failed to setup webhook: ${error}`);
|
|
1162
|
+
throw error;
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
async send(content) {
|
|
1166
|
+
const webhook = await this.getWebhook();
|
|
1167
|
+
const options = {};
|
|
1168
|
+
if (SendableComponentBuilder.isSendableComponent(content)) {
|
|
1169
|
+
const t = SendableComponentBuilder.buildMessage(content);
|
|
1170
|
+
options.embeds = t.embeds;
|
|
1171
|
+
options.components = t.components;
|
|
1172
|
+
} else if (typeof content == "string") {
|
|
1173
|
+
options.content = content;
|
|
1174
|
+
} else if (typeof content === "object") {
|
|
1175
|
+
Object.assign(options, content);
|
|
1176
|
+
} else {
|
|
1177
|
+
options.content = content;
|
|
1178
|
+
}
|
|
1179
|
+
if (this.channel instanceof ThreadChannel2) {
|
|
1180
|
+
options.threadId = this.channel.id;
|
|
1181
|
+
}
|
|
1182
|
+
try {
|
|
1183
|
+
const message = await webhook.send(options);
|
|
1184
|
+
Log.info(`Webhook sent to ${this.channel.id}: ${content}`);
|
|
1185
|
+
return message;
|
|
1186
|
+
} catch (error) {
|
|
1187
|
+
Log.error(`Webhook send failed ${this.channel.id}: ${error}`);
|
|
1188
|
+
return null;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* Quick success embed
|
|
1193
|
+
*/
|
|
1194
|
+
async success(message) {
|
|
1195
|
+
return await this.send(EmbedManager.success(message));
|
|
1196
|
+
}
|
|
1197
|
+
/**
|
|
1198
|
+
* Quick error embed
|
|
1199
|
+
*/
|
|
1200
|
+
async error(message) {
|
|
1201
|
+
return await this.send(EmbedManager.error(message));
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* Delete webhook
|
|
1205
|
+
*/
|
|
1206
|
+
async delete(reason) {
|
|
1207
|
+
if (!this.webhook) return;
|
|
1208
|
+
try {
|
|
1209
|
+
await this.webhook.delete(reason ?? "Deleted by WebhookManager");
|
|
1210
|
+
Log.info(`Webhook ${this.webhook.id} deleted`);
|
|
1211
|
+
} catch (error) {
|
|
1212
|
+
if (error.message.includes("Unknown Webhook")) {
|
|
1213
|
+
Log.warn("Webhook already deleted");
|
|
1214
|
+
} else {
|
|
1215
|
+
Log.error(`Failed to delete webhook: ${error}`);
|
|
1216
|
+
}
|
|
1217
|
+
} finally {
|
|
1218
|
+
this.webhook = null;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
};
|
|
1222
|
+
|
|
1223
|
+
// src/manager/guild/ChannelManager/GuildTextChannelManager.ts
|
|
1224
|
+
import { TextChannel as TextChannel4, ChannelType } from "discord.js";
|
|
1225
|
+
|
|
1226
|
+
// src/manager/guild/ChannelManager/GuildMessageManager.ts
|
|
1227
|
+
var GuildMessageManager = class {
|
|
1228
|
+
/**
|
|
1229
|
+
* Impl
|
|
1230
|
+
*/
|
|
1231
|
+
static async send(channelId, content_or_component_or_options) {
|
|
1232
|
+
try {
|
|
1233
|
+
const channel = await GuildTextChannelManager.find(channelId);
|
|
1234
|
+
if (!channel) {
|
|
1235
|
+
Log.error(`Channel ${channelId} not found in guild`);
|
|
1236
|
+
return null;
|
|
1237
|
+
}
|
|
1238
|
+
let payload;
|
|
1239
|
+
if (typeof content_or_component_or_options === "string") {
|
|
1240
|
+
payload = SendableComponentBuilder.buildMessage(content_or_component_or_options);
|
|
1241
|
+
} else if (SendableComponentBuilder.isSendableComponent(content_or_component_or_options) || Array.isArray(content_or_component_or_options)) {
|
|
1242
|
+
payload = SendableComponentBuilder.buildMessage(content_or_component_or_options);
|
|
1243
|
+
} else {
|
|
1244
|
+
payload = content_or_component_or_options;
|
|
1245
|
+
}
|
|
1246
|
+
return await channel.send(payload);
|
|
1247
|
+
} catch (error) {
|
|
1248
|
+
Log.error(`Failed to send message to ${channelId}: ${error}`);
|
|
1249
|
+
throw error;
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
/**
|
|
1253
|
+
* Delete message
|
|
1254
|
+
*/
|
|
1255
|
+
static async delete(channelId, messageId) {
|
|
1256
|
+
try {
|
|
1257
|
+
const channel = await GuildTextChannelManager.find(channelId);
|
|
1258
|
+
if (!channel) {
|
|
1259
|
+
Log.error(`Channel ${channelId} not found`);
|
|
1260
|
+
return false;
|
|
1261
|
+
}
|
|
1262
|
+
const message = await channel.messages.fetch(messageId);
|
|
1263
|
+
await message.delete();
|
|
1264
|
+
Log.info(`Deleted message ${messageId} from ${channelId}`);
|
|
1265
|
+
return true;
|
|
1266
|
+
} catch (error) {
|
|
1267
|
+
Log.error(`Failed to delete message ${messageId} from ${channelId}: ${error}`);
|
|
1268
|
+
return false;
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
/**
|
|
1272
|
+
* Fetch messages (last X messages, default 10)
|
|
1273
|
+
*/
|
|
1274
|
+
static async fetch(channelId, limit = 10) {
|
|
1275
|
+
try {
|
|
1276
|
+
const channel = await GuildTextChannelManager.find(channelId);
|
|
1277
|
+
if (!channel) {
|
|
1278
|
+
Log.error(`Channel ${channelId} not found`);
|
|
1279
|
+
return [];
|
|
1280
|
+
}
|
|
1281
|
+
const messages = await channel.messages.fetch({ limit });
|
|
1282
|
+
Log.info(`Fetched ${messages.size} messages from ${channelId}`);
|
|
1283
|
+
return Array.from(messages.values());
|
|
1284
|
+
} catch (error) {
|
|
1285
|
+
Log.error(`Failed to fetch messages from ${channelId}: ${error}`);
|
|
1286
|
+
return [];
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
/**
|
|
1290
|
+
* Fetch single message
|
|
1291
|
+
*/
|
|
1292
|
+
static async fetchOne(channelId, messageId) {
|
|
1293
|
+
try {
|
|
1294
|
+
const channel = await GuildTextChannelManager.find(channelId);
|
|
1295
|
+
if (!channel) {
|
|
1296
|
+
Log.error(`Channel ${channelId} not found`);
|
|
1297
|
+
return null;
|
|
1298
|
+
}
|
|
1299
|
+
const message = await channel.messages.fetch(messageId);
|
|
1300
|
+
return message;
|
|
1301
|
+
} catch (error) {
|
|
1302
|
+
Log.error(`Failed to fetch message ${messageId} from ${channelId}: ${error}`);
|
|
1303
|
+
return null;
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
};
|
|
1307
|
+
|
|
1308
|
+
// src/manager/guild/ChannelManager/GuildChannelManager.ts
|
|
1309
|
+
var _GuildChannelManager = class _GuildChannelManager {
|
|
1310
|
+
/**
|
|
1311
|
+
* Recherche un channel par ID dans une guild spécifique
|
|
1312
|
+
*/
|
|
1313
|
+
static async findInGuild(guildId, channelId) {
|
|
1314
|
+
try {
|
|
1315
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1316
|
+
if (!guild) {
|
|
1317
|
+
Log.warn(`Guild ${guildId} not found`);
|
|
1318
|
+
return null;
|
|
1319
|
+
}
|
|
1320
|
+
const channel = await guild.channels.fetch(channelId);
|
|
1321
|
+
return channel ?? null;
|
|
1322
|
+
} catch (error) {
|
|
1323
|
+
Log.error(`Failed to find channel ${channelId} in guild ${guildId}: ${error}`);
|
|
1324
|
+
return null;
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
static async find(channelId) {
|
|
1328
|
+
for (const guild of Bot.client.guilds.cache.values()) {
|
|
1329
|
+
try {
|
|
1330
|
+
const channel = await guild.channels.fetch(channelId);
|
|
1331
|
+
if (channel) return channel;
|
|
1332
|
+
} catch {
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
Log.warn(`Channel ${channelId} not found in any guild`);
|
|
1336
|
+
return null;
|
|
1337
|
+
}
|
|
1338
|
+
static findAll(guildId) {
|
|
1339
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1340
|
+
if (!guild) {
|
|
1341
|
+
Log.warn(`Guild ${guildId} not found`);
|
|
1342
|
+
return [];
|
|
1343
|
+
}
|
|
1344
|
+
return Array.from(guild.channels.cache.values());
|
|
1345
|
+
}
|
|
1346
|
+
/**
|
|
1347
|
+
* Recherche channels par nom (insensible à la casse)
|
|
1348
|
+
*/
|
|
1349
|
+
static findByName(guildId, name) {
|
|
1350
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1351
|
+
if (!guild) {
|
|
1352
|
+
Log.warn(`Guild ${guildId} not found`);
|
|
1353
|
+
return [];
|
|
1354
|
+
}
|
|
1355
|
+
return Array.from(guild.channels.cache.values()).filter(
|
|
1356
|
+
(channel) => channel.name.toLowerCase().includes(name.toLowerCase())
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1359
|
+
static async _create(guildId, options) {
|
|
1360
|
+
try {
|
|
1361
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1362
|
+
if (!guild) {
|
|
1363
|
+
throw new Error(`Guild ${guildId} not found`);
|
|
1364
|
+
}
|
|
1365
|
+
const channel = await guild.channels.create(options);
|
|
1366
|
+
Log.info(`Created channel ${channel.name} (${channel.id}) in guild ${guildId}`);
|
|
1367
|
+
return channel;
|
|
1368
|
+
} catch (error) {
|
|
1369
|
+
Log.error(`Failed to create channel in guild ${guildId}: ${error}`);
|
|
1370
|
+
throw error;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
static async delete(channelId) {
|
|
1374
|
+
try {
|
|
1375
|
+
const channel = await _GuildChannelManager.find(channelId);
|
|
1376
|
+
if (!channel) {
|
|
1377
|
+
throw new Error(`Channel ${channelId} not found`);
|
|
1378
|
+
}
|
|
1379
|
+
await channel.delete();
|
|
1380
|
+
Log.info(`Deleted channel ${channelId}`);
|
|
1381
|
+
return true;
|
|
1382
|
+
} catch (error) {
|
|
1383
|
+
Log.error(`Failed to delete channel ${channelId}: ${error}`);
|
|
1384
|
+
throw error;
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
};
|
|
1388
|
+
_GuildChannelManager.message = GuildMessageManager;
|
|
1389
|
+
var GuildChannelManager = _GuildChannelManager;
|
|
1390
|
+
|
|
1391
|
+
// src/manager/guild/ChannelManager/GuildTextChannelManager.ts
|
|
1392
|
+
var GuildTextChannelManager = class extends GuildChannelManager {
|
|
1393
|
+
static async findInGuild(guildId, channelId) {
|
|
1394
|
+
const channel = await super.findInGuild(guildId, channelId);
|
|
1395
|
+
return channel?.isTextBased() ? channel : null;
|
|
1396
|
+
}
|
|
1397
|
+
static async find(channelId) {
|
|
1398
|
+
const channel = await super.find(channelId);
|
|
1399
|
+
return channel?.isTextBased() ? channel : null;
|
|
1400
|
+
}
|
|
1401
|
+
static findAll(guildId) {
|
|
1402
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1403
|
+
if (!guild) {
|
|
1404
|
+
Log.warn(`Guild ${guildId} not found`);
|
|
1405
|
+
return [];
|
|
1406
|
+
}
|
|
1407
|
+
return Array.from(guild.channels.cache.values()).filter((c) => c instanceof TextChannel4);
|
|
1408
|
+
}
|
|
1409
|
+
static async create(guildId, name, options) {
|
|
1410
|
+
return await super._create(guildId, {
|
|
1411
|
+
name,
|
|
1412
|
+
type: ChannelType.GuildText,
|
|
1413
|
+
...options
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1416
|
+
};
|
|
1417
|
+
|
|
1418
|
+
// src/manager/messages/ReactionManager.ts
|
|
1419
|
+
var ReactionManager = class {
|
|
1420
|
+
/**
|
|
1421
|
+
* Add a reaction to a message
|
|
1422
|
+
*/
|
|
1423
|
+
static async add(channelId, messageId, emoji) {
|
|
1424
|
+
try {
|
|
1425
|
+
const channel = await GuildTextChannelManager.find(channelId);
|
|
1426
|
+
if (!channel) {
|
|
1427
|
+
throw new Error(`Channel ${channelId} not found`);
|
|
1428
|
+
}
|
|
1429
|
+
if (!channel.isTextBased()) {
|
|
1430
|
+
throw new Error(`Channel ${channelId} is not text based`);
|
|
1431
|
+
}
|
|
1432
|
+
const message = await channel.messages.fetch(messageId);
|
|
1433
|
+
await message.react(emoji);
|
|
1434
|
+
Log.info(`Added reaction ${emoji} to message ${messageId}`);
|
|
1435
|
+
} catch (error) {
|
|
1436
|
+
Log.error(`Failed to add reaction to ${messageId}: ${error}`);
|
|
1437
|
+
throw error;
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
/**
|
|
1441
|
+
* Delete a reaction from a user
|
|
1442
|
+
*/
|
|
1443
|
+
static async remove(channelId, messageId, emoji, userId) {
|
|
1444
|
+
try {
|
|
1445
|
+
const channel = await GuildTextChannelManager.find(channelId);
|
|
1446
|
+
if (!channel) {
|
|
1447
|
+
throw new Error(`Channel ${channelId} not found`);
|
|
1448
|
+
}
|
|
1449
|
+
const message = await channel.messages.fetch(messageId);
|
|
1450
|
+
const reaction = message.reactions.resolve(emoji);
|
|
1451
|
+
if (!reaction) {
|
|
1452
|
+
throw new Error(`Reaction ${emoji} not found on message ${messageId}`);
|
|
1453
|
+
}
|
|
1454
|
+
const user = await Bot.client.users.fetch(userId);
|
|
1455
|
+
await reaction.users.remove(user);
|
|
1456
|
+
Log.info(`Removed reaction ${emoji} from user ${userId} on message ${messageId}`);
|
|
1457
|
+
} catch (error) {
|
|
1458
|
+
Log.error(`Failed to remove reaction from ${messageId}: ${error}`);
|
|
1459
|
+
throw error;
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
/**
|
|
1463
|
+
* Get all reaction of a message
|
|
1464
|
+
*/
|
|
1465
|
+
static async getAll(channelId, messageId) {
|
|
1466
|
+
try {
|
|
1467
|
+
const channel = await GuildTextChannelManager.find(channelId);
|
|
1468
|
+
if (!channel) {
|
|
1469
|
+
throw new Error(`Channel ${channelId} not found`);
|
|
1470
|
+
}
|
|
1471
|
+
const message = await channel.messages.fetch(messageId);
|
|
1472
|
+
const reactions = message.reactions.cache;
|
|
1473
|
+
const reactionList = [];
|
|
1474
|
+
for (const reaction of reactions.values()) {
|
|
1475
|
+
const users = await reaction.users.fetch();
|
|
1476
|
+
reactionList.push({
|
|
1477
|
+
emoji: reaction.emoji,
|
|
1478
|
+
count: reaction.count,
|
|
1479
|
+
users: Array.from(users.values())
|
|
1480
|
+
});
|
|
1481
|
+
}
|
|
1482
|
+
Log.info(`Fetched ${reactionList.length} reactions for message ${messageId}`);
|
|
1483
|
+
return reactionList;
|
|
1484
|
+
} catch (error) {
|
|
1485
|
+
Log.error(`Failed to fetch reactions for ${messageId}: ${error}`);
|
|
1486
|
+
throw error;
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
/**
|
|
1490
|
+
* Delete all reaction
|
|
1491
|
+
*/
|
|
1492
|
+
static async clear(channelId, messageId) {
|
|
1493
|
+
try {
|
|
1494
|
+
const channel = await GuildTextChannelManager.find(channelId);
|
|
1495
|
+
if (!channel) {
|
|
1496
|
+
throw new Error(`Channel ${channelId} not found`);
|
|
1497
|
+
}
|
|
1498
|
+
const message = await channel.messages.fetch(messageId);
|
|
1499
|
+
await message.reactions.removeAll();
|
|
1500
|
+
Log.info(`Cleared all reactions from message ${messageId}`);
|
|
1501
|
+
} catch (error) {
|
|
1502
|
+
Log.error(`Failed to clear reactions from ${messageId}: ${error}`);
|
|
1503
|
+
throw error;
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
};
|
|
1507
|
+
|
|
1508
|
+
// src/manager/guild/GuildManager.ts
|
|
1509
|
+
import {
|
|
1510
|
+
Guild as Guild2,
|
|
1511
|
+
VoiceChannel as VoiceChannel2,
|
|
1512
|
+
StageChannel as StageChannel2
|
|
1513
|
+
} from "discord.js";
|
|
1514
|
+
|
|
1515
|
+
// src/manager/direct/BasicUserManager.ts
|
|
1516
|
+
import { GuildMember as GuildMember2 } from "discord.js";
|
|
1517
|
+
var BasicUserManager = class {
|
|
1518
|
+
/**
|
|
1519
|
+
* Find member in specific guild
|
|
1520
|
+
*/
|
|
1521
|
+
static async findInGuild(guildId, memberId) {
|
|
1522
|
+
try {
|
|
1523
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1524
|
+
if (!guild) throw new Error(`Guild ${guildId} not found`);
|
|
1525
|
+
const member = await guild.members.fetch({ user: memberId, force: true });
|
|
1526
|
+
return member ?? null;
|
|
1527
|
+
} catch (error) {
|
|
1528
|
+
Log.error(`UserManager: Member ${memberId} not found in ${guildId}`);
|
|
1529
|
+
return null;
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
/**
|
|
1533
|
+
* Check if user is still in guild
|
|
1534
|
+
*/
|
|
1535
|
+
static async isInGuild(guildId, userId) {
|
|
1536
|
+
try {
|
|
1537
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1538
|
+
if (!guild) return false;
|
|
1539
|
+
await guild.members.fetch({ user: userId, force: true });
|
|
1540
|
+
return true;
|
|
1541
|
+
} catch (error) {
|
|
1542
|
+
return error.code !== 10007;
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
/**
|
|
1546
|
+
* Impl
|
|
1547
|
+
*/
|
|
1548
|
+
static async send(user_id_or_user, content_or_component_or_options, component) {
|
|
1549
|
+
try {
|
|
1550
|
+
let user;
|
|
1551
|
+
if (typeof user_id_or_user === "string") {
|
|
1552
|
+
user = await Bot.client.users.fetch(user_id_or_user);
|
|
1553
|
+
} else {
|
|
1554
|
+
user = user_id_or_user;
|
|
1555
|
+
}
|
|
1556
|
+
const dmChannel = await user.createDM();
|
|
1557
|
+
let payload;
|
|
1558
|
+
if (component && typeof content_or_component_or_options == "string") {
|
|
1559
|
+
payload = SendableComponentBuilder.buildMessage(
|
|
1560
|
+
content_or_component_or_options,
|
|
1561
|
+
component
|
|
1562
|
+
);
|
|
1563
|
+
} else if (typeof content_or_component_or_options === "string") {
|
|
1564
|
+
payload = SendableComponentBuilder.buildMessage(content_or_component_or_options);
|
|
1565
|
+
} else if (SendableComponentBuilder.isSendableComponent(content_or_component_or_options)) {
|
|
1566
|
+
payload = SendableComponentBuilder.buildMessage(content_or_component_or_options);
|
|
1567
|
+
} else {
|
|
1568
|
+
payload = content_or_component_or_options;
|
|
1569
|
+
}
|
|
1570
|
+
const message = await dmChannel.send(payload);
|
|
1571
|
+
if (user instanceof GuildMember2) {
|
|
1572
|
+
Log.info(`Sent DM to ${user.id} (${user.user.username}): "${(payload.content || "Embed/Component").substring(0, 50)}..."`);
|
|
1573
|
+
} else {
|
|
1574
|
+
Log.info(`Sent DM to ${user.id} (${user.username}): "${(payload.content || "Embed/Component").substring(0, 50)}..."`);
|
|
1575
|
+
}
|
|
1576
|
+
return message;
|
|
1577
|
+
} catch (error) {
|
|
1578
|
+
Log.error(`Failed to send DM to ${user_id_or_user}: ${error}`);
|
|
1579
|
+
throw new Error(`Cannot send DM to ${user_id_or_user}`);
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
};
|
|
1583
|
+
|
|
1584
|
+
// src/manager/guild/GuildUserManager.ts
|
|
1585
|
+
import { Guild } from "discord.js";
|
|
1586
|
+
import { setTimeout as setTimeout2 } from "timers/promises";
|
|
1587
|
+
var MAX_NICKNAME_LENGTH = 32;
|
|
1588
|
+
var GuildUserManager = class extends BasicUserManager {
|
|
1589
|
+
static async find(userId, guild) {
|
|
1590
|
+
try {
|
|
1591
|
+
if (guild instanceof Guild) {
|
|
1592
|
+
return await guild.members.fetch(userId);
|
|
1593
|
+
} else {
|
|
1594
|
+
return await (await GuildManager.find(guild)).members.fetch(userId);
|
|
1595
|
+
}
|
|
1596
|
+
} catch (error) {
|
|
1597
|
+
Log.error(`UserManager: Member ${userId} not found`);
|
|
1598
|
+
return null;
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
static async rename(member, nickname, maxAttempts = 3) {
|
|
1602
|
+
if (nickname.length > MAX_NICKNAME_LENGTH) {
|
|
1603
|
+
nickname = nickname.slice(0, MAX_NICKNAME_LENGTH);
|
|
1604
|
+
}
|
|
1605
|
+
for (let attempts = 0; attempts < maxAttempts; attempts++) {
|
|
1606
|
+
try {
|
|
1607
|
+
const oldName = member.displayName;
|
|
1608
|
+
await member.setNickname(nickname.trim());
|
|
1609
|
+
Log.info(`Renaming user: ${oldName} \u2192 ${nickname.trim()}`);
|
|
1610
|
+
await setTimeout2(1500);
|
|
1611
|
+
return true;
|
|
1612
|
+
} catch (error) {
|
|
1613
|
+
console.error(`Attempt ${attempts + 1} failed when renaming ${member.displayName} into ${nickname.trim()}:`, error);
|
|
1614
|
+
await setTimeout2(1e3);
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
Bot.log.info(EmbedManager.error(`Failed to rename ${member.displayName} to ${nickname.trim()} after ${maxAttempts} attempts.`));
|
|
1618
|
+
return false;
|
|
1619
|
+
}
|
|
1620
|
+
/**
|
|
1621
|
+
* Check if user is banned from guild
|
|
1622
|
+
*/
|
|
1623
|
+
static async isBanned(guildId, userId) {
|
|
1624
|
+
try {
|
|
1625
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1626
|
+
if (!guild) {
|
|
1627
|
+
Log.warn(`Guild ${guildId} not found`);
|
|
1628
|
+
return false;
|
|
1629
|
+
}
|
|
1630
|
+
const ban = await guild.bans.fetch(userId);
|
|
1631
|
+
return !!ban;
|
|
1632
|
+
} catch (error) {
|
|
1633
|
+
Log.debug(`User ${userId} is not banned from guild ${guildId}`);
|
|
1634
|
+
return false;
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
/**
|
|
1638
|
+
* Deconnect a member from a voice
|
|
1639
|
+
*/
|
|
1640
|
+
static async deconnectFromVoice(guildId, memberId) {
|
|
1641
|
+
try {
|
|
1642
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1643
|
+
if (!guild) {
|
|
1644
|
+
throw new Error(`Guild ${guildId} not found`);
|
|
1645
|
+
}
|
|
1646
|
+
const member = await guild.members.fetch(memberId);
|
|
1647
|
+
if (!member.voice.channel) {
|
|
1648
|
+
throw new Error(`Member ${memberId} is not in a voice channel`);
|
|
1649
|
+
}
|
|
1650
|
+
await member.voice.disconnect();
|
|
1651
|
+
Log.info(`Disconnected member ${memberId} from voice in guild ${guildId}`);
|
|
1652
|
+
} catch (error) {
|
|
1653
|
+
Log.error(`Failed to disconnect member ${memberId} from voice in ${guildId}: ${error}`);
|
|
1654
|
+
throw error;
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
/**
|
|
1658
|
+
* Check if a member is in voice
|
|
1659
|
+
*/
|
|
1660
|
+
static async isInVoice(memberId, guildId) {
|
|
1661
|
+
try {
|
|
1662
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1663
|
+
if (!guild) return false;
|
|
1664
|
+
const member = await guild.members.fetch(memberId);
|
|
1665
|
+
return member.voice.channelId !== null;
|
|
1666
|
+
} catch (error) {
|
|
1667
|
+
Log.debug(`Member ${memberId} not found or not in voice in guild ${guildId}`);
|
|
1668
|
+
return false;
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
/**
|
|
1672
|
+
* Mute a member
|
|
1673
|
+
*/
|
|
1674
|
+
static async mute(guildId, memberId, reason) {
|
|
1675
|
+
try {
|
|
1676
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1677
|
+
if (!guild) throw new Error(`Guild ${guildId} not found`);
|
|
1678
|
+
const member = await guild.members.fetch(memberId);
|
|
1679
|
+
await member.voice.setMute(true, reason);
|
|
1680
|
+
Log.info(`Server muted ${memberId} in guild ${guildId}: ${reason || "No reason"}`);
|
|
1681
|
+
} catch (error) {
|
|
1682
|
+
Log.error(`Failed to server mute ${memberId} in ${guildId}:, error`);
|
|
1683
|
+
throw error;
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
/**
|
|
1687
|
+
* Unmute a member
|
|
1688
|
+
*/
|
|
1689
|
+
static async unmute(guildId, memberId, reason) {
|
|
1690
|
+
try {
|
|
1691
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1692
|
+
if (!guild) throw new Error(`Guild ${guildId} not found`);
|
|
1693
|
+
const member = await guild.members.fetch(memberId);
|
|
1694
|
+
await member.voice.setMute(false, reason);
|
|
1695
|
+
Log.info(`Server unmuted ${memberId} in guild ${guildId}: ${reason || "No reason"}`);
|
|
1696
|
+
} catch (error) {
|
|
1697
|
+
Log.error(`Failed to server unmute ${memberId} in ${guildId}: ${error}`);
|
|
1698
|
+
throw error;
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
/**
|
|
1702
|
+
* Deafen a member
|
|
1703
|
+
*/
|
|
1704
|
+
static async deafen(guildId, memberId, reason) {
|
|
1705
|
+
try {
|
|
1706
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1707
|
+
if (!guild) throw new Error(`Guild ${guildId} not found`);
|
|
1708
|
+
const member = await guild.members.fetch(memberId);
|
|
1709
|
+
await member.voice.setDeaf(true, reason);
|
|
1710
|
+
Log.info(`Server deafened ${memberId} in guild ${guildId}: ${reason || "No reason"}`);
|
|
1711
|
+
} catch (error) {
|
|
1712
|
+
Log.error(`Failed to server deafen ${memberId} in ${guildId}: ${error}`);
|
|
1713
|
+
throw error;
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
/**
|
|
1717
|
+
* Undeafen member voice
|
|
1718
|
+
*/
|
|
1719
|
+
static async undeafen(guildId, memberId, reason) {
|
|
1720
|
+
try {
|
|
1721
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1722
|
+
if (!guild) throw new Error(`Guild ${guildId} not found`);
|
|
1723
|
+
const member = await guild.members.fetch(memberId);
|
|
1724
|
+
await member.voice.setDeaf(false, reason);
|
|
1725
|
+
Log.info(`Server undeafened ${memberId} in guild ${guildId}: ${reason || "No reason"}`);
|
|
1726
|
+
} catch (error) {
|
|
1727
|
+
Log.error(`Failed to server undeafen ${memberId} in ${guildId}: ${error}`);
|
|
1728
|
+
throw error;
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
/**
|
|
1732
|
+
* Timeout a member
|
|
1733
|
+
*/
|
|
1734
|
+
static async timeout(guildId, memberId, duration, reason) {
|
|
1735
|
+
try {
|
|
1736
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1737
|
+
if (!guild) throw new Error(`Guild ${guildId} not found`);
|
|
1738
|
+
const member = await guild.members.fetch(memberId);
|
|
1739
|
+
const expires = Date.now() + duration;
|
|
1740
|
+
await member.timeout(expires, reason);
|
|
1741
|
+
Log.info(`Timed out ${memberId} for ${duration}ms in guild ${guildId}: ${reason || "No reason"}`);
|
|
1742
|
+
} catch (error) {
|
|
1743
|
+
Log.error(`Failed to timeout ${memberId} in ${guildId}: ${error}`);
|
|
1744
|
+
throw error;
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
/**
|
|
1748
|
+
* Remove the timeout of a member
|
|
1749
|
+
*/
|
|
1750
|
+
static async untimeout(guildId, memberId, reason) {
|
|
1751
|
+
try {
|
|
1752
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1753
|
+
if (!guild) throw new Error(`Guild ${guildId} not found`);
|
|
1754
|
+
const member = await guild.members.fetch(memberId);
|
|
1755
|
+
await member.timeout(null, reason);
|
|
1756
|
+
Log.info(`Untimed out ${memberId} in guild ${guildId}: ${reason || "No reason"}`);
|
|
1757
|
+
} catch (error) {
|
|
1758
|
+
Log.error(`Failed to untimeout ${memberId} in ${guildId}: ${error}`);
|
|
1759
|
+
throw error;
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
/**
|
|
1763
|
+
* Kick a member
|
|
1764
|
+
*/
|
|
1765
|
+
static async kick(guildId, memberId, reason) {
|
|
1766
|
+
try {
|
|
1767
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1768
|
+
if (!guild) throw new Error(`Guild ${guildId} not found`);
|
|
1769
|
+
const member = await guild.members.fetch(memberId);
|
|
1770
|
+
await member.kick(reason);
|
|
1771
|
+
Log.info(`Kicked ${memberId} from guild ${guildId}: ${reason || "No reason"}`);
|
|
1772
|
+
} catch (error) {
|
|
1773
|
+
Log.error(`Failed to kick ${memberId} from ${guildId}: ${error}`);
|
|
1774
|
+
throw error;
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
static async ban(guildId, userId, banOption) {
|
|
1778
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1779
|
+
if (!guild) {
|
|
1780
|
+
throw new Error(`Guild ${guildId} not found`);
|
|
1781
|
+
}
|
|
1782
|
+
try {
|
|
1783
|
+
await guild.members.ban(userId, banOption);
|
|
1784
|
+
Log.info(`Banned user ${userId} from guild ${guildId}`);
|
|
1785
|
+
} catch (error) {
|
|
1786
|
+
Log.error(`Failed to ban user ${userId} from guild ${guildId}: ${error}`);
|
|
1787
|
+
throw error;
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
static async unban(guildId, userId, reason) {
|
|
1791
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1792
|
+
if (!guild) {
|
|
1793
|
+
throw new Error(`Guild ${guildId} not found`);
|
|
1794
|
+
}
|
|
1795
|
+
try {
|
|
1796
|
+
await guild.members.unban(userId, reason);
|
|
1797
|
+
Log.info(`Unbanned user ${userId} from guild ${guildId}`);
|
|
1798
|
+
} catch (error) {
|
|
1799
|
+
Log.error(`Failed to unban user ${userId} from guild ${guildId}: ${error}`);
|
|
1800
|
+
throw error;
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
};
|
|
1804
|
+
|
|
1805
|
+
// src/manager/guild/RoleManager.ts
|
|
1806
|
+
var RoleManager = class {
|
|
1807
|
+
/**
|
|
1808
|
+
* Add role - CACHE ONLY
|
|
1809
|
+
* @param member - GuildMember ALREADY FETCHED
|
|
1810
|
+
* @param roleId - Role ID (string)
|
|
1811
|
+
*/
|
|
1812
|
+
static async add(member, roleId) {
|
|
1813
|
+
try {
|
|
1814
|
+
const role = member.roles.cache.get(roleId);
|
|
1815
|
+
if (!role) {
|
|
1816
|
+
Log.warn(`Role ${roleId} not found in cache`);
|
|
1817
|
+
return false;
|
|
1818
|
+
}
|
|
1819
|
+
await member.roles.add(role);
|
|
1820
|
+
Log.info(`\u2705 Added ${role.name} to ${member.displayName}`);
|
|
1821
|
+
return true;
|
|
1822
|
+
} catch (error) {
|
|
1823
|
+
Log.error(`Failed to add role ${roleId}: ${error}`);
|
|
1824
|
+
return false;
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
/**
|
|
1828
|
+
* Remove role - CACHE ONLY
|
|
1829
|
+
* @param member - GuildMember ALREADY FETCHED
|
|
1830
|
+
* @param roleIdOrName - Role ID or name
|
|
1831
|
+
*/
|
|
1832
|
+
static async remove(member, roleIdOrName) {
|
|
1833
|
+
try {
|
|
1834
|
+
let role;
|
|
1835
|
+
if (typeof roleIdOrName === "string" && roleIdOrName.length === 18) {
|
|
1836
|
+
role = member.roles.cache.get(roleIdOrName);
|
|
1837
|
+
} else {
|
|
1838
|
+
role = member.roles.cache.find(
|
|
1839
|
+
(r) => r.id === roleIdOrName || r.name.toLowerCase() === roleIdOrName.toString().toLowerCase()
|
|
1840
|
+
);
|
|
1841
|
+
}
|
|
1842
|
+
if (!role) {
|
|
1843
|
+
Log.warn(`Role ${roleIdOrName} not found for ${member.displayName}`);
|
|
1844
|
+
return false;
|
|
1845
|
+
}
|
|
1846
|
+
await member.roles.remove(role);
|
|
1847
|
+
Log.info(`\u2705 Removed ${role.name} from ${member.displayName}`);
|
|
1848
|
+
return true;
|
|
1849
|
+
} catch (error) {
|
|
1850
|
+
Log.error(`Failed to remove role ${roleIdOrName}: ${error}`);
|
|
1851
|
+
return false;
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
/**
|
|
1855
|
+
* Toggle role (add/remove)
|
|
1856
|
+
*/
|
|
1857
|
+
static async toggle(member, roleIdOrName) {
|
|
1858
|
+
const role = member.roles.cache.get(roleIdOrName) || member.roles.cache.find((r) => r.name.toLowerCase() === roleIdOrName.toString().toLowerCase());
|
|
1859
|
+
if (!role) {
|
|
1860
|
+
Log.warn(`Role ${roleIdOrName} not found`);
|
|
1861
|
+
throw new Error(`Role not found`);
|
|
1862
|
+
}
|
|
1863
|
+
if (member.roles.cache.has(role.id)) {
|
|
1864
|
+
await this.remove(member, role.id);
|
|
1865
|
+
return "removed";
|
|
1866
|
+
} else {
|
|
1867
|
+
await this.add(member, role.id);
|
|
1868
|
+
return "added";
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
/**
|
|
1872
|
+
* Check if member has role
|
|
1873
|
+
*/
|
|
1874
|
+
static hasRole(member, roleIdOrName) {
|
|
1875
|
+
if (typeof roleIdOrName === "string" && roleIdOrName.length === 18) {
|
|
1876
|
+
return member.roles.cache.has(roleIdOrName);
|
|
1877
|
+
}
|
|
1878
|
+
return member.roles.cache.some(
|
|
1879
|
+
(r) => r.id === roleIdOrName || r.name.toLowerCase() === roleIdOrName.toString().toLowerCase()
|
|
1880
|
+
);
|
|
1881
|
+
}
|
|
1882
|
+
};
|
|
1883
|
+
|
|
1884
|
+
// src/manager/guild/ChannelManager/ForumChannelManager.ts
|
|
1885
|
+
import { ChannelType as ChannelType2, ForumChannel } from "discord.js";
|
|
1886
|
+
var ForumChannelManager = class extends GuildChannelManager {
|
|
1887
|
+
static async findInGuild(guildId, channelId) {
|
|
1888
|
+
const channel = await super.findInGuild(guildId, channelId);
|
|
1889
|
+
return channel instanceof ForumChannel ? channel : null;
|
|
1890
|
+
}
|
|
1891
|
+
static async find(channelId) {
|
|
1892
|
+
const channel = await super.find(channelId);
|
|
1893
|
+
return channel instanceof ForumChannel ? channel : null;
|
|
1894
|
+
}
|
|
1895
|
+
static findAll(guildId) {
|
|
1896
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1897
|
+
if (!guild) {
|
|
1898
|
+
Log.warn(`Guild ${guildId} not found`);
|
|
1899
|
+
return [];
|
|
1900
|
+
}
|
|
1901
|
+
return Array.from(guild.channels.cache.values()).filter((c) => c instanceof ForumChannel);
|
|
1902
|
+
}
|
|
1903
|
+
static async create(guildId, name, options) {
|
|
1904
|
+
return await super._create(guildId, {
|
|
1905
|
+
name,
|
|
1906
|
+
type: ChannelType2.GuildForum,
|
|
1907
|
+
...options
|
|
1908
|
+
});
|
|
1909
|
+
}
|
|
1910
|
+
};
|
|
1911
|
+
|
|
1912
|
+
// src/manager/guild/ChannelManager/NewsChannelManager.ts
|
|
1913
|
+
import { ChannelType as ChannelType3, NewsChannel } from "discord.js";
|
|
1914
|
+
var NewsChannelManager = class extends GuildChannelManager {
|
|
1915
|
+
static async findInGuild(guildId, channelId) {
|
|
1916
|
+
const channel = await super.findInGuild(guildId, channelId);
|
|
1917
|
+
return channel instanceof NewsChannel ? channel : null;
|
|
1918
|
+
}
|
|
1919
|
+
static async find(channelId) {
|
|
1920
|
+
const channel = await super.find(channelId);
|
|
1921
|
+
return channel instanceof NewsChannel ? channel : null;
|
|
1922
|
+
}
|
|
1923
|
+
static findAll(guildId) {
|
|
1924
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1925
|
+
if (!guild) {
|
|
1926
|
+
Log.warn(`Guild ${guildId} not found`);
|
|
1927
|
+
return [];
|
|
1928
|
+
}
|
|
1929
|
+
return Array.from(guild.channels.cache.values()).filter((c) => c instanceof NewsChannel);
|
|
1930
|
+
}
|
|
1931
|
+
static async create(guildId, name, options) {
|
|
1932
|
+
return await super._create(guildId, {
|
|
1933
|
+
name,
|
|
1934
|
+
type: ChannelType3.GuildAnnouncement,
|
|
1935
|
+
...options
|
|
1936
|
+
});
|
|
1937
|
+
}
|
|
1938
|
+
};
|
|
1939
|
+
|
|
1940
|
+
// src/manager/guild/ChannelManager/StageChannelManager.ts
|
|
1941
|
+
import { ChannelType as ChannelType4, StageChannel } from "discord.js";
|
|
1942
|
+
var StageChannelManager = class extends GuildChannelManager {
|
|
1943
|
+
static async findInGuild(guildId, channelId) {
|
|
1944
|
+
const channel = await super.findInGuild(guildId, channelId);
|
|
1945
|
+
return channel instanceof StageChannel ? channel : null;
|
|
1946
|
+
}
|
|
1947
|
+
static async find(channelId) {
|
|
1948
|
+
const channel = await super.find(channelId);
|
|
1949
|
+
return channel instanceof StageChannel ? channel : null;
|
|
1950
|
+
}
|
|
1951
|
+
static findAll(guildId) {
|
|
1952
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
1953
|
+
if (!guild) {
|
|
1954
|
+
Log.warn(`Guild ${guildId} not found`);
|
|
1955
|
+
return [];
|
|
1956
|
+
}
|
|
1957
|
+
return Array.from(guild.channels.cache.values()).filter((c) => c instanceof StageChannel);
|
|
1958
|
+
}
|
|
1959
|
+
static async create(guildId, name, options) {
|
|
1960
|
+
return await super._create(guildId, {
|
|
1961
|
+
name,
|
|
1962
|
+
type: ChannelType4.GuildStageVoice,
|
|
1963
|
+
...options
|
|
1964
|
+
});
|
|
1965
|
+
}
|
|
1966
|
+
};
|
|
1967
|
+
|
|
1968
|
+
// src/manager/guild/ChannelManager/ThreadChannelManager.ts
|
|
1969
|
+
var ThreadChannelManager = class {
|
|
1970
|
+
static async findInGuild(guildId, channelId) {
|
|
1971
|
+
const channel = await GuildChannelManager.findInGuild(guildId, channelId);
|
|
1972
|
+
return channel?.isThread() ? channel : null;
|
|
1973
|
+
}
|
|
1974
|
+
static async find(channelId) {
|
|
1975
|
+
const channel = await GuildChannelManager.find(channelId);
|
|
1976
|
+
return channel?.isThread() ? channel : null;
|
|
1977
|
+
}
|
|
1978
|
+
static findAll(guildId) {
|
|
1979
|
+
const channels = GuildChannelManager.findAll(guildId);
|
|
1980
|
+
return channels.filter((c) => c.isThread());
|
|
1981
|
+
}
|
|
1982
|
+
static async createFromChannel(parentId, options) {
|
|
1983
|
+
const channel = await GuildTextChannelManager.find(parentId);
|
|
1984
|
+
if (!channel || !channel.isTextBased()) {
|
|
1985
|
+
throw new Error("Parent must be a text-based channel");
|
|
1986
|
+
}
|
|
1987
|
+
const thread = await channel.threads.create(options);
|
|
1988
|
+
return thread;
|
|
1989
|
+
}
|
|
1990
|
+
static async createFromMessage(message, options) {
|
|
1991
|
+
const channel = await GuildChannelManager.find(message.id);
|
|
1992
|
+
if (!channel) throw new Error("Message channel not found");
|
|
1993
|
+
return await message.startThread(options);
|
|
1994
|
+
}
|
|
1995
|
+
/**
|
|
1996
|
+
* Impl
|
|
1997
|
+
*/
|
|
1998
|
+
static async send(channelId, content_or_component_or_options) {
|
|
1999
|
+
if (typeof content_or_component_or_options == "string") {
|
|
2000
|
+
return await GuildTextChannelManager.message.send(channelId, content_or_component_or_options);
|
|
2001
|
+
} else if (SendableComponentBuilder.isSendableComponent(content_or_component_or_options) || Array.isArray(content_or_component_or_options)) {
|
|
2002
|
+
return await GuildTextChannelManager.message.send(channelId, content_or_component_or_options);
|
|
2003
|
+
} else {
|
|
2004
|
+
return await GuildTextChannelManager.message.send(channelId, content_or_component_or_options);
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
};
|
|
2008
|
+
|
|
2009
|
+
// src/manager/guild/ChannelManager/GuildVoiceChannelManager.ts
|
|
2010
|
+
import { ChannelType as ChannelType5, VoiceChannel } from "discord.js";
|
|
2011
|
+
var GuildVoiceChannelManager = class extends GuildChannelManager {
|
|
2012
|
+
static async findInGuild(guildId, channelId) {
|
|
2013
|
+
const channel = await super.findInGuild(guildId, channelId);
|
|
2014
|
+
return channel?.isVoiceBased() ? channel : null;
|
|
2015
|
+
}
|
|
2016
|
+
static async find(channelId) {
|
|
2017
|
+
const channel = await super.find(channelId);
|
|
2018
|
+
return channel?.isVoiceBased() ? channel : null;
|
|
2019
|
+
}
|
|
2020
|
+
static findAll(guildId) {
|
|
2021
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
2022
|
+
if (!guild) {
|
|
2023
|
+
Log.warn(`Guild ${guildId} not found`);
|
|
2024
|
+
return [];
|
|
2025
|
+
}
|
|
2026
|
+
return Array.from(guild.channels.cache.values()).filter((c) => c instanceof VoiceChannel);
|
|
2027
|
+
}
|
|
2028
|
+
static async create(guildId, name, options) {
|
|
2029
|
+
return await super._create(guildId, {
|
|
2030
|
+
name,
|
|
2031
|
+
type: ChannelType5.GuildVoice,
|
|
2032
|
+
...options
|
|
2033
|
+
});
|
|
2034
|
+
}
|
|
2035
|
+
};
|
|
2036
|
+
|
|
2037
|
+
// src/manager/guild/ChannelManager/GuildChannelList.ts
|
|
2038
|
+
var GuildChannelList = class {
|
|
2039
|
+
};
|
|
2040
|
+
GuildChannelList.forum = ForumChannelManager;
|
|
2041
|
+
GuildChannelList.any = GuildChannelManager;
|
|
2042
|
+
GuildChannelList.news = NewsChannelManager;
|
|
2043
|
+
GuildChannelList.stage = StageChannelManager;
|
|
2044
|
+
GuildChannelList.text = GuildTextChannelManager;
|
|
2045
|
+
GuildChannelList.thread = ThreadChannelManager;
|
|
2046
|
+
GuildChannelList.voice = GuildVoiceChannelManager;
|
|
2047
|
+
|
|
2048
|
+
// src/manager/guild/InviteManager.ts
|
|
2049
|
+
var InviteManager = class {
|
|
2050
|
+
/**
|
|
2051
|
+
* Create an invite for a channel
|
|
2052
|
+
*/
|
|
2053
|
+
static async create(channelId, options = {}) {
|
|
2054
|
+
try {
|
|
2055
|
+
const channel = await GuildChannelManager.find(channelId);
|
|
2056
|
+
if (!channel) {
|
|
2057
|
+
throw new Error(`Channel ${channelId} not found`);
|
|
2058
|
+
}
|
|
2059
|
+
const guild = channel.guild;
|
|
2060
|
+
const inviteOptions = {
|
|
2061
|
+
maxAge: options.maxAge ?? 86400,
|
|
2062
|
+
maxUses: options.maxUses ?? 0,
|
|
2063
|
+
temporary: options.temporary ?? false,
|
|
2064
|
+
reason: options.reason
|
|
2065
|
+
};
|
|
2066
|
+
const invite = await guild.invites.create(channelId, inviteOptions);
|
|
2067
|
+
Log.info(`Created invite ${invite.code} for channel ${channelId}`);
|
|
2068
|
+
return invite;
|
|
2069
|
+
} catch (error) {
|
|
2070
|
+
Log.error(`Failed to create invite for channel ${channelId}: ${error}`);
|
|
2071
|
+
throw error;
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
/**
|
|
2075
|
+
* Delete an invitation
|
|
2076
|
+
*/
|
|
2077
|
+
static async delete(invite) {
|
|
2078
|
+
try {
|
|
2079
|
+
await invite.delete();
|
|
2080
|
+
Log.info(`Deleted invite ${invite.code} from guild ${invite.guild?.id}`);
|
|
2081
|
+
return true;
|
|
2082
|
+
} catch (error) {
|
|
2083
|
+
Log.error(`Failed to delete invite ${invite.code}: ${error}`);
|
|
2084
|
+
return false;
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
/**
|
|
2088
|
+
* List every invitation from a guild
|
|
2089
|
+
*/
|
|
2090
|
+
static async list(guildId) {
|
|
2091
|
+
try {
|
|
2092
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
2093
|
+
if (!guild) {
|
|
2094
|
+
throw new Error(`Guild ${guildId} not found`);
|
|
2095
|
+
}
|
|
2096
|
+
const invites = await guild.invites.fetch();
|
|
2097
|
+
const inviteList = Array.from(invites.values());
|
|
2098
|
+
Log.info(`Fetched ${inviteList.length} invites for guild ${guildId}`);
|
|
2099
|
+
return inviteList;
|
|
2100
|
+
} catch (error) {
|
|
2101
|
+
Log.error(`Failed to fetch invites for guild ${guildId}: ${error}`);
|
|
2102
|
+
throw error;
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
};
|
|
2106
|
+
|
|
2107
|
+
// src/manager/guild/GuildManager.ts
|
|
2108
|
+
var GuildManager = class {
|
|
2109
|
+
static list() {
|
|
2110
|
+
return Array.from(Bot.client.guilds.cache.values());
|
|
2111
|
+
}
|
|
2112
|
+
static async find(guild_id) {
|
|
2113
|
+
return await Bot.client.guilds.fetch(guild_id);
|
|
2114
|
+
}
|
|
2115
|
+
/**
|
|
2116
|
+
* Search channel by ID (TextChannel, DMChannel, ThreadChannel)
|
|
2117
|
+
*/
|
|
2118
|
+
static async searchChannel(guildId, channelId) {
|
|
2119
|
+
try {
|
|
2120
|
+
return await GuildChannelManager.findInGuild(guildId, channelId);
|
|
2121
|
+
} catch (error) {
|
|
2122
|
+
Log.error(`Failed to fetch channel ${channelId}: ${error}`);
|
|
2123
|
+
return null;
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
/**
|
|
2127
|
+
* Search guild member by ID
|
|
2128
|
+
*/
|
|
2129
|
+
static async searchMember(memberId, guildId) {
|
|
2130
|
+
try {
|
|
2131
|
+
return await this.user.findInGuild(guildId, guildId);
|
|
2132
|
+
} catch (error) {
|
|
2133
|
+
Log.error(`Failed to fetch member ${memberId} in guild ${guildId}: ${error}`);
|
|
2134
|
+
return null;
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
/**
|
|
2138
|
+
* Check if member is still in guild
|
|
2139
|
+
*/
|
|
2140
|
+
static async isMemberInGuild(memberId, guildId) {
|
|
2141
|
+
try {
|
|
2142
|
+
return await this.user.isInGuild(memberId, guildId);
|
|
2143
|
+
} catch (error) {
|
|
2144
|
+
return error.code !== 10007;
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
/**
|
|
2148
|
+
* Fetch all members with retry (heavy operation)
|
|
2149
|
+
*/
|
|
2150
|
+
static async fetchAllMembers(guildId, MAX_ATTEMPTS = 3, RETRY_DELAY = Time.minute.MIN_05.toMilliseconds()) {
|
|
2151
|
+
let guild;
|
|
2152
|
+
if (guildId instanceof Guild2) {
|
|
2153
|
+
guild = guildId;
|
|
2154
|
+
} else {
|
|
2155
|
+
let tmp = Bot.client.guilds.cache.get(guildId);
|
|
2156
|
+
if (!tmp) throw new Error(`Guild ${guildId} not found`);
|
|
2157
|
+
guild = tmp;
|
|
2158
|
+
}
|
|
2159
|
+
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
2160
|
+
try {
|
|
2161
|
+
Log.info(`UserManager: Fetching ${guild.name} members (attempt ${attempt})`);
|
|
2162
|
+
return await guild.members.fetch();
|
|
2163
|
+
} catch (error) {
|
|
2164
|
+
Log.error(`UserManager: Fetch failed (attempt ${attempt}): ${error}`);
|
|
2165
|
+
if (attempt < MAX_ATTEMPTS) {
|
|
2166
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY));
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
throw new Error(`Failed to fetch members after ${MAX_ATTEMPTS} attempts`);
|
|
2171
|
+
}
|
|
2172
|
+
static async listban(guildId, limit) {
|
|
2173
|
+
const guild = Bot.client.guilds.cache.get(guildId);
|
|
2174
|
+
if (!guild) {
|
|
2175
|
+
throw new Error(`Guild ${guildId} not found`);
|
|
2176
|
+
}
|
|
2177
|
+
try {
|
|
2178
|
+
const bans = await guild.bans.fetch({ limit });
|
|
2179
|
+
return Array.from(bans.values());
|
|
2180
|
+
} catch (error) {
|
|
2181
|
+
Log.error(`Failed to list bans in guild ${guildId}: ${error}`);
|
|
2182
|
+
throw error;
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
static async moveMember(memberId, fromChannelId, toChannelId) {
|
|
2186
|
+
try {
|
|
2187
|
+
const guild = Bot.client.guilds.cache.find(
|
|
2188
|
+
(g) => g.channels.cache.has(fromChannelId) || g.channels.cache.has(toChannelId)
|
|
2189
|
+
);
|
|
2190
|
+
if (!guild) {
|
|
2191
|
+
throw new Error(`Guild containing channels ${fromChannelId} or ${toChannelId} not found`);
|
|
2192
|
+
}
|
|
2193
|
+
const member = await guild.members.fetch(memberId).catch(() => null);
|
|
2194
|
+
if (!member) {
|
|
2195
|
+
throw new Error(`Member ${memberId} not found in guild ${guild.id}`);
|
|
2196
|
+
}
|
|
2197
|
+
const fromChannel = guild.channels.cache.get(fromChannelId);
|
|
2198
|
+
const toChannel = guild.channels.cache.get(toChannelId);
|
|
2199
|
+
if (!fromChannel) {
|
|
2200
|
+
throw new Error(`From channel ${fromChannelId} not found`);
|
|
2201
|
+
}
|
|
2202
|
+
if (!toChannel) {
|
|
2203
|
+
throw new Error(`To channel ${toChannelId} not found`);
|
|
2204
|
+
}
|
|
2205
|
+
if (!(fromChannel instanceof VoiceChannel2 || fromChannel instanceof StageChannel2)) {
|
|
2206
|
+
throw new Error(`From channel ${fromChannelId} is not a voice/stage channel`);
|
|
2207
|
+
}
|
|
2208
|
+
if (!(toChannel instanceof VoiceChannel2 || toChannel instanceof StageChannel2)) {
|
|
2209
|
+
throw new Error(`To channel ${toChannelId} is not a voice/stage channel`);
|
|
2210
|
+
}
|
|
2211
|
+
if (member.voice.channelId !== fromChannelId) {
|
|
2212
|
+
throw new Error(`Member ${memberId} is not in channel ${fromChannelId}`);
|
|
2213
|
+
}
|
|
2214
|
+
try {
|
|
2215
|
+
await member.voice.setChannel(toChannel);
|
|
2216
|
+
Log.info(`Moved member ${memberId} from ${fromChannelId} to ${toChannelId}`);
|
|
2217
|
+
} catch (error) {
|
|
2218
|
+
Log.error(`Failed to move member ${memberId} from ${fromChannelId} to ${toChannelId}: ${error}`);
|
|
2219
|
+
throw error;
|
|
2220
|
+
}
|
|
2221
|
+
return true;
|
|
2222
|
+
} catch (e) {
|
|
2223
|
+
Log.error(`Failed to move member ${e}`);
|
|
2224
|
+
return false;
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
};
|
|
2228
|
+
GuildManager.role = RoleManager;
|
|
2229
|
+
GuildManager.user = GuildUserManager;
|
|
2230
|
+
GuildManager.channel = GuildChannelList;
|
|
2231
|
+
GuildManager.invite = InviteManager;
|
|
2232
|
+
|
|
2233
|
+
// src/manager/direct/UserManager.ts
|
|
2234
|
+
var UserManager = class extends BasicUserManager {
|
|
2235
|
+
static async find(userId) {
|
|
2236
|
+
try {
|
|
2237
|
+
return await Bot.client.users.fetch(userId);
|
|
2238
|
+
} catch (error) {
|
|
2239
|
+
Log.error(`UserManager: Member ${userId} not found`);
|
|
2240
|
+
return null;
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
};
|
|
2244
|
+
|
|
2245
|
+
// src/manager/interactions/ModalManager.ts
|
|
2246
|
+
import {
|
|
2247
|
+
ActionRowBuilder as ActionRowBuilder2,
|
|
2248
|
+
ModalBuilder,
|
|
2249
|
+
TextInputBuilder,
|
|
2250
|
+
TextInputStyle
|
|
2251
|
+
} from "discord.js";
|
|
2252
|
+
var ModalManager = class _ModalManager {
|
|
2253
|
+
/**
|
|
2254
|
+
* Load modal from JSON file and return ModalBuilder
|
|
2255
|
+
*/
|
|
2256
|
+
static async load(filename) {
|
|
2257
|
+
try {
|
|
2258
|
+
const file = await FileManager.readJsonFile(`./handlers/${"modals" /* MODAL */}/${filename}`);
|
|
2259
|
+
if (!file) return false;
|
|
2260
|
+
return _ModalManager.jsonToBuilder(file);
|
|
2261
|
+
} catch {
|
|
2262
|
+
return false;
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
/**
|
|
2266
|
+
* List all modal files
|
|
2267
|
+
*/
|
|
2268
|
+
static async list() {
|
|
2269
|
+
try {
|
|
2270
|
+
const files = await FileManager.listJsonFiles(`./handlers/${"modals" /* MODAL */}`);
|
|
2271
|
+
return files || [];
|
|
2272
|
+
} catch {
|
|
2273
|
+
return false;
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
static jsonToBuilder(json) {
|
|
2277
|
+
const modal = new ModalBuilder().setCustomId(json.customId).setTitle(json.title.slice(0, 45));
|
|
2278
|
+
const actionRows = [];
|
|
2279
|
+
for (const fieldJson of json.fields) {
|
|
2280
|
+
const input = this.fieldJsonToInput(fieldJson);
|
|
2281
|
+
const row = new ActionRowBuilder2().addComponents(input);
|
|
2282
|
+
actionRows.push(row);
|
|
2283
|
+
}
|
|
2284
|
+
return modal.addComponents(...actionRows);
|
|
2285
|
+
}
|
|
2286
|
+
static fieldJsonToInput(fieldJson) {
|
|
2287
|
+
const input = new TextInputBuilder().setCustomId(fieldJson.customId).setLabel(fieldJson.title.slice(0, 45)).setPlaceholder(fieldJson.placeholder || "Enter value...").setRequired(fieldJson.required !== false).setMinLength(fieldJson.minLength || 0).setMaxLength(fieldJson.maxLength || 400);
|
|
2288
|
+
const style = fieldJson.style;
|
|
2289
|
+
if (typeof style === "number") {
|
|
2290
|
+
input.setStyle(style);
|
|
2291
|
+
} else {
|
|
2292
|
+
switch (style) {
|
|
2293
|
+
case "Number":
|
|
2294
|
+
case "Phone":
|
|
2295
|
+
case "Date":
|
|
2296
|
+
input.setStyle(TextInputStyle.Short);
|
|
2297
|
+
input.setPlaceholder(
|
|
2298
|
+
style === "Number" ? "123" : style === "Phone" ? "+33 6 12 34 56 78" : "2024-02-05"
|
|
2299
|
+
);
|
|
2300
|
+
break;
|
|
2301
|
+
default:
|
|
2302
|
+
input.setStyle(TextInputStyle.Short);
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
return input;
|
|
2306
|
+
}
|
|
2307
|
+
static parseNumber(value) {
|
|
2308
|
+
if (!/^\d+$/.test(value)) return null;
|
|
2309
|
+
const num = parseInt(value);
|
|
2310
|
+
return isNaN(num) ? null : num;
|
|
2311
|
+
}
|
|
2312
|
+
static parsePhone(value) {
|
|
2313
|
+
const clean = value.replace(/[\s\-\(\)]/g, "");
|
|
2314
|
+
if (/^(06|07|09)\d{8}$/.test(clean) || /^(\+33|0033)?[6-9]\d{8}$/.test(clean)) {
|
|
2315
|
+
if (clean.startsWith("06") || clean.startsWith("07") || clean.startsWith("09")) {
|
|
2316
|
+
return "+33" + clean.slice(2);
|
|
2317
|
+
}
|
|
2318
|
+
return clean.startsWith("0033") ? "+33" + clean.slice(4) : clean;
|
|
2319
|
+
}
|
|
2320
|
+
return null;
|
|
2321
|
+
}
|
|
2322
|
+
static parseDate(value) {
|
|
2323
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
2324
|
+
const [year, month, day] = value.split("-").map(Number);
|
|
2325
|
+
const date = new Date(year, month - 1, day);
|
|
2326
|
+
return isNaN(date.getTime()) ? null : date;
|
|
2327
|
+
}
|
|
2328
|
+
if (/^\d{2}\/\d{2}\/\d{4}$/.test(value)) {
|
|
2329
|
+
const [day, month, year] = value.split("/").map(Number);
|
|
2330
|
+
const date = new Date(year, month - 1, day);
|
|
2331
|
+
return isNaN(date.getTime()) ? null : date;
|
|
2332
|
+
}
|
|
2333
|
+
return null;
|
|
2334
|
+
}
|
|
2335
|
+
};
|
|
2336
|
+
|
|
2337
|
+
// src/manager/interactions/SelectMenuManager.ts
|
|
2338
|
+
import {
|
|
2339
|
+
ActionRowBuilder as ActionRowBuilder3,
|
|
2340
|
+
StringSelectMenuBuilder,
|
|
2341
|
+
StringSelectMenuOptionBuilder,
|
|
2342
|
+
UserSelectMenuBuilder,
|
|
2343
|
+
RoleSelectMenuBuilder,
|
|
2344
|
+
MentionableSelectMenuBuilder,
|
|
2345
|
+
ChannelSelectMenuBuilder
|
|
2346
|
+
} from "discord.js";
|
|
2347
|
+
var SelectMenuManager = class {
|
|
2348
|
+
/**
|
|
2349
|
+
* Creates base StringSelectMenu - SIMPLE API !
|
|
2350
|
+
*/
|
|
2351
|
+
static create(customId, placeholder = "Select an option...") {
|
|
2352
|
+
return new StringSelectMenuBuilder().setCustomId(customId).setPlaceholder(placeholder).setMinValues(1).setMaxValues(1);
|
|
2353
|
+
}
|
|
2354
|
+
/**
|
|
2355
|
+
* Quick StringSelectMenu
|
|
2356
|
+
*/
|
|
2357
|
+
static simple(customId, options, placeholder = "Choose an option") {
|
|
2358
|
+
const menu = this.create(customId, placeholder);
|
|
2359
|
+
menu.addOptions(
|
|
2360
|
+
options.map((opt) => {
|
|
2361
|
+
return this.option(opt);
|
|
2362
|
+
})
|
|
2363
|
+
);
|
|
2364
|
+
return menu;
|
|
2365
|
+
}
|
|
2366
|
+
/**
|
|
2367
|
+
* Pagination menu
|
|
2368
|
+
*/
|
|
2369
|
+
static paginated(customId, options, pageSize = 25) {
|
|
2370
|
+
const row = new ActionRowBuilder3();
|
|
2371
|
+
for (let i = 0; i < options.length; i += pageSize) {
|
|
2372
|
+
const pageOptions = options.slice(i, i + pageSize);
|
|
2373
|
+
const menu = new StringSelectMenuBuilder().setCustomId(`${customId}_page_${Math.floor(i / pageSize)}`).setPlaceholder(`Page ${Math.floor(i / pageSize) + 1}`).addOptions(pageOptions.map((opt) => {
|
|
2374
|
+
return this.option(opt);
|
|
2375
|
+
}));
|
|
2376
|
+
row.addComponents(menu);
|
|
2377
|
+
}
|
|
2378
|
+
return row;
|
|
2379
|
+
}
|
|
2380
|
+
/**
|
|
2381
|
+
* User Select Menu (Components V2)
|
|
2382
|
+
*/
|
|
2383
|
+
static users(customId, placeholder = "Select users...") {
|
|
2384
|
+
return new UserSelectMenuBuilder().setCustomId(customId).setPlaceholder(placeholder).setMinValues(1).setMaxValues(25);
|
|
2385
|
+
}
|
|
2386
|
+
/**
|
|
2387
|
+
* Role Select Menu (Components V2)
|
|
2388
|
+
*/
|
|
2389
|
+
static roles(customId, placeholder = "Select roles...") {
|
|
2390
|
+
return new RoleSelectMenuBuilder().setCustomId(customId).setPlaceholder(placeholder).setMinValues(1).setMaxValues(25);
|
|
2391
|
+
}
|
|
2392
|
+
/**
|
|
2393
|
+
* Mentionable Select Menu (Components V2)
|
|
2394
|
+
*/
|
|
2395
|
+
static mentionables(customId, placeholder = "Select users/roles...") {
|
|
2396
|
+
return new MentionableSelectMenuBuilder().setCustomId(customId).setPlaceholder(placeholder).setMinValues(1).setMaxValues(25);
|
|
2397
|
+
}
|
|
2398
|
+
/**
|
|
2399
|
+
* Channel Select Menu (Components V2)
|
|
2400
|
+
*/
|
|
2401
|
+
static channels(customId, placeholder = "Select channels...", channelTypes = []) {
|
|
2402
|
+
return new ChannelSelectMenuBuilder().setCustomId(customId).setPlaceholder(placeholder).setMinValues(1).setMaxValues(25).setChannelTypes(...channelTypes);
|
|
2403
|
+
}
|
|
2404
|
+
static option(option) {
|
|
2405
|
+
if (Array.isArray(option)) {
|
|
2406
|
+
return option.map((opt) => this._createOption(opt));
|
|
2407
|
+
}
|
|
2408
|
+
return this._createOption(option);
|
|
2409
|
+
}
|
|
2410
|
+
static _createOption(option) {
|
|
2411
|
+
const builder = new StringSelectMenuOptionBuilder().setLabel(option.label).setValue(option.value);
|
|
2412
|
+
option.description && builder.setDescription(option.description);
|
|
2413
|
+
option.emoji && builder.setEmoji(option.emoji);
|
|
2414
|
+
return builder;
|
|
2415
|
+
}
|
|
2416
|
+
/**
|
|
2417
|
+
* Fluent API pour personnaliser
|
|
2418
|
+
*/
|
|
2419
|
+
static placeholder(menu, placeholder) {
|
|
2420
|
+
return menu.setPlaceholder(placeholder);
|
|
2421
|
+
}
|
|
2422
|
+
static minMax(menu, min, max) {
|
|
2423
|
+
return menu.setMinValues(min).setMaxValues(Math.min(max, 25));
|
|
2424
|
+
}
|
|
2425
|
+
static disabled(menu, disabled) {
|
|
2426
|
+
return menu.setDisabled(disabled);
|
|
2427
|
+
}
|
|
2428
|
+
/**
|
|
2429
|
+
* ActionRow
|
|
2430
|
+
*/
|
|
2431
|
+
static row(component) {
|
|
2432
|
+
return new ActionRowBuilder3().addComponents(component);
|
|
2433
|
+
}
|
|
2434
|
+
/**
|
|
2435
|
+
* Rows multiples (5 max)
|
|
2436
|
+
*/
|
|
2437
|
+
static rows(...components) {
|
|
2438
|
+
return components.slice(0, 5).map(
|
|
2439
|
+
(component) => this.row(component)
|
|
2440
|
+
);
|
|
2441
|
+
}
|
|
2442
|
+
};
|
|
2443
|
+
|
|
2444
|
+
// src/utils/SimpleMutex.ts
|
|
2445
|
+
var SimpleMutex = class {
|
|
2446
|
+
// File d'attente des fonctions de résolution
|
|
2447
|
+
constructor() {
|
|
2448
|
+
this._locked = false;
|
|
2449
|
+
this.queue = [];
|
|
2450
|
+
}
|
|
2451
|
+
/**
|
|
2452
|
+
* Verrouille le mutex. Si le mutex est déjà verrouillé, la méthode retourne une promesse qui sera résolue une fois que le mutex sera disponible.
|
|
2453
|
+
* @returns Une promesse résolue lorsque le mutex est verrouillé.
|
|
2454
|
+
*/
|
|
2455
|
+
async lock() {
|
|
2456
|
+
if (this._locked) {
|
|
2457
|
+
return new Promise((resolve) => {
|
|
2458
|
+
this.queue.push(resolve);
|
|
2459
|
+
});
|
|
2460
|
+
}
|
|
2461
|
+
this._locked = true;
|
|
2462
|
+
return Promise.resolve();
|
|
2463
|
+
}
|
|
2464
|
+
/**
|
|
2465
|
+
* Déverrouille le mutex. Si une file d'attente existe, débloque le prochain élément dans la file.
|
|
2466
|
+
*/
|
|
2467
|
+
unlock() {
|
|
2468
|
+
if (this.queue.length > 0) {
|
|
2469
|
+
const nextResolve = this.queue.shift();
|
|
2470
|
+
if (nextResolve) {
|
|
2471
|
+
nextResolve();
|
|
2472
|
+
}
|
|
2473
|
+
return;
|
|
2474
|
+
}
|
|
2475
|
+
this._locked = false;
|
|
2476
|
+
}
|
|
2477
|
+
get locked() {
|
|
2478
|
+
return this._locked;
|
|
2479
|
+
}
|
|
2480
|
+
};
|
|
2481
|
+
|
|
2482
|
+
// package.json
|
|
2483
|
+
var package_default = {
|
|
2484
|
+
name: "@spatulox/simplediscordbot",
|
|
2485
|
+
version: "1.0.31",
|
|
2486
|
+
author: "Spatulox",
|
|
2487
|
+
description: "Simple discord bot framework to set up a bot under 30 secondes",
|
|
2488
|
+
exports: {
|
|
2489
|
+
types: "./dist/index.d.ts",
|
|
2490
|
+
import: "./dist/index.js",
|
|
2491
|
+
require: "./dist/index.js"
|
|
2492
|
+
},
|
|
2493
|
+
types: "./dist/index.d.ts",
|
|
2494
|
+
scripts: {
|
|
2495
|
+
build: "rm -r dist/ && tsup",
|
|
2496
|
+
patch: "npm run build && npm version patch",
|
|
2497
|
+
pub: "npm run patch && npm publish --access public",
|
|
2498
|
+
"test-pack": "npm run patch && npm publish --access public",
|
|
2499
|
+
dev: "nodemon --exec tsx src/test/index.ts"
|
|
2500
|
+
},
|
|
2501
|
+
license: "MIT",
|
|
2502
|
+
dependencies: {
|
|
2503
|
+
"@spatulox/discord-interaction-manager": "^1.0.8",
|
|
2504
|
+
"discord.js": "^14.25.1"
|
|
2505
|
+
},
|
|
2506
|
+
devDependencies: {
|
|
2507
|
+
"@types/node": "^22.14.0",
|
|
2508
|
+
"@types/node-schedule": "^2.1.7",
|
|
2509
|
+
dotenv: "^17.2.4",
|
|
2510
|
+
nodemon: "^3.1.9",
|
|
2511
|
+
tsup: "^8.5.1",
|
|
2512
|
+
tsx: "^4.20.3",
|
|
2513
|
+
typescript: "^5.9.3"
|
|
2514
|
+
},
|
|
2515
|
+
keywords: [
|
|
2516
|
+
"discord",
|
|
2517
|
+
"framework",
|
|
2518
|
+
"bot",
|
|
2519
|
+
"client",
|
|
2520
|
+
"discordjs",
|
|
2521
|
+
"discord.js",
|
|
2522
|
+
"node"
|
|
2523
|
+
],
|
|
2524
|
+
bugs: {
|
|
2525
|
+
url: "https://github.com/Spatulox/SimpleDiscordBot/issues"
|
|
2526
|
+
}
|
|
2527
|
+
};
|
|
2528
|
+
|
|
2529
|
+
// src/SimpleDiscordBotInfo.ts
|
|
2530
|
+
var SimpleDiscordBotInfo = {
|
|
2531
|
+
name: package_default.name,
|
|
2532
|
+
version: package_default.license,
|
|
2533
|
+
author: package_default.author,
|
|
2534
|
+
description: package_default.description,
|
|
2535
|
+
license: package_default.license
|
|
2536
|
+
};
|
|
2537
|
+
export {
|
|
2538
|
+
Bot,
|
|
2539
|
+
BotEnv,
|
|
2540
|
+
DiscordRegex,
|
|
2541
|
+
EmbedColor,
|
|
2542
|
+
EmbedManager,
|
|
2543
|
+
FileManager,
|
|
2544
|
+
GuildManager,
|
|
2545
|
+
Log,
|
|
2546
|
+
ModalManager,
|
|
2547
|
+
ReactionManager,
|
|
2548
|
+
SelectMenuManager,
|
|
2549
|
+
SimpleDiscordBotInfo,
|
|
2550
|
+
SimpleMutex,
|
|
2551
|
+
Time,
|
|
2552
|
+
UserManager,
|
|
2553
|
+
WebhookManager
|
|
2554
|
+
};
|