bakit 2.0.0-alpha.2 → 2.0.0-alpha.20
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/dist/cli.js +81 -0
- package/dist/index.d.ts +256 -106
- package/dist/index.js +753 -258
- package/dist/loader/hooks.js +75 -0
- package/dist/loader/register.js +14 -0
- package/package.json +17 -6
package/dist/index.js
CHANGED
|
@@ -1,134 +1,334 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import glob from 'tiny-glob';
|
|
1
|
+
import { register } from 'module';
|
|
2
|
+
import { MessageChannel } from 'worker_threads';
|
|
3
|
+
import { GatewayIntentBits, Events, Client, Collection, IntentsBitField, SlashCommandBuilder, SlashCommandStringOption, SlashCommandNumberOption, SlashCommandUserOption, ChatInputCommandInteraction, Message } from 'discord.js';
|
|
5
4
|
import { inspect } from 'util';
|
|
6
|
-
import { posix } from 'path';
|
|
5
|
+
import { posix, relative, sep, join, dirname } from 'path';
|
|
6
|
+
import glob from 'tiny-glob';
|
|
7
|
+
import z4 from 'zod';
|
|
8
|
+
import { pathToFileURL } from 'url';
|
|
9
|
+
import { existsSync, mkdirSync, rmSync } from 'fs';
|
|
10
|
+
import { mkdir, writeFile, readFile, rm } from 'fs/promises';
|
|
11
|
+
import { createHash } from 'crypto';
|
|
7
12
|
|
|
8
|
-
|
|
9
|
-
var
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*
|
|
23
|
-
* These are passed directly to the `Client` constructor when initializing the bot.
|
|
24
|
-
*
|
|
25
|
-
* @see {@link https://discord.js.org/docs/packages/discord.js/main/ClientOptions:Interface}
|
|
26
|
-
*/
|
|
27
|
-
clientOptions: z.custom().optional(),
|
|
28
|
-
/**
|
|
29
|
-
* The path to the main project source directory.
|
|
30
|
-
*
|
|
31
|
-
* @defaultvalue `src`
|
|
32
|
-
*/
|
|
33
|
-
entryDir: z.string().default("src")
|
|
13
|
+
var __defProp = Object.defineProperty;
|
|
14
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
15
|
+
var __esm = (fn, res) => function() {
|
|
16
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
17
|
+
};
|
|
18
|
+
var __export = (target, all) => {
|
|
19
|
+
for (var name in all)
|
|
20
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// src/loader/register.ts
|
|
24
|
+
var register_exports = {};
|
|
25
|
+
__export(register_exports, {
|
|
26
|
+
unload: () => unload
|
|
34
27
|
});
|
|
35
|
-
function
|
|
36
|
-
|
|
28
|
+
function unload(module) {
|
|
29
|
+
port2.postMessage({ type: "unload", target: module });
|
|
37
30
|
}
|
|
38
|
-
var
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
31
|
+
var port1, port2, hookPath, init_register = __esm({
|
|
32
|
+
"src/loader/register.ts"() {
|
|
33
|
+
(({ port1, port2 } = new MessageChannel())), hookPath = new URL("./hooks.js", import.meta.url).href;
|
|
34
|
+
register(hookPath, import.meta.url, {
|
|
35
|
+
data: { port: port1 },
|
|
36
|
+
transferList: [port1]
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
var ParamUserType = /* @__PURE__ */ ((ParamUserType2) => (ParamUserType2.Bot = "bot", ParamUserType2.Normal = "normal", ParamUserType2.Any = "any", ParamUserType2))(ParamUserType || {}), BaseParamSchema = z4.object({
|
|
41
|
+
name: z4.string(),
|
|
42
|
+
description: z4.string().optional(),
|
|
43
|
+
required: z4.boolean().default(true)
|
|
44
|
+
}), StringParamSchema = BaseParamSchema.extend({
|
|
45
|
+
maxLength: z4.number().min(1).optional(),
|
|
46
|
+
minLength: z4.number().min(1).optional()
|
|
47
|
+
}), NumberParamSchema = BaseParamSchema.extend({
|
|
48
|
+
maxValue: z4.number().optional(),
|
|
49
|
+
minValue: z4.number().optional()
|
|
50
|
+
}), UserParamSchema = BaseParamSchema.extend({});
|
|
51
|
+
var INTENT_GROUPS = {
|
|
52
|
+
[GatewayIntentBits.Guilds]: [
|
|
53
|
+
Events.GuildCreate,
|
|
54
|
+
Events.GuildDelete,
|
|
55
|
+
Events.GuildUpdate,
|
|
56
|
+
Events.GuildUnavailable,
|
|
57
|
+
Events.GuildRoleCreate,
|
|
58
|
+
Events.GuildRoleDelete,
|
|
59
|
+
Events.GuildRoleUpdate,
|
|
60
|
+
Events.ChannelCreate,
|
|
61
|
+
Events.ChannelDelete,
|
|
62
|
+
Events.ChannelUpdate,
|
|
63
|
+
Events.ChannelPinsUpdate,
|
|
64
|
+
Events.ThreadCreate,
|
|
65
|
+
Events.ThreadDelete,
|
|
66
|
+
Events.ThreadUpdate,
|
|
67
|
+
Events.ThreadListSync,
|
|
68
|
+
Events.ThreadMemberUpdate,
|
|
69
|
+
Events.ThreadMembersUpdate,
|
|
70
|
+
Events.StageInstanceCreate,
|
|
71
|
+
Events.StageInstanceUpdate,
|
|
72
|
+
Events.StageInstanceDelete
|
|
73
|
+
],
|
|
74
|
+
[GatewayIntentBits.GuildMembers]: [
|
|
75
|
+
Events.GuildMemberAdd,
|
|
76
|
+
Events.GuildMemberUpdate,
|
|
77
|
+
Events.GuildMemberRemove,
|
|
78
|
+
Events.ThreadMembersUpdate
|
|
79
|
+
],
|
|
80
|
+
[GatewayIntentBits.GuildModeration]: [Events.GuildAuditLogEntryCreate, Events.GuildBanAdd, Events.GuildBanRemove],
|
|
81
|
+
[GatewayIntentBits.GuildExpressions]: [
|
|
82
|
+
Events.GuildEmojiCreate,
|
|
83
|
+
Events.GuildEmojiDelete,
|
|
84
|
+
Events.GuildEmojiUpdate,
|
|
85
|
+
Events.GuildStickerCreate,
|
|
86
|
+
Events.GuildStickerDelete,
|
|
87
|
+
Events.GuildStickerUpdate,
|
|
88
|
+
Events.GuildSoundboardSoundCreate,
|
|
89
|
+
Events.GuildSoundboardSoundUpdate,
|
|
90
|
+
Events.GuildSoundboardSoundDelete,
|
|
91
|
+
Events.GuildSoundboardSoundsUpdate
|
|
92
|
+
],
|
|
93
|
+
[GatewayIntentBits.GuildIntegrations]: [Events.GuildIntegrationsUpdate],
|
|
94
|
+
[GatewayIntentBits.GuildWebhooks]: [Events.WebhooksUpdate],
|
|
95
|
+
[GatewayIntentBits.GuildInvites]: [Events.InviteCreate, Events.InviteDelete],
|
|
96
|
+
[GatewayIntentBits.GuildVoiceStates]: [Events.VoiceStateUpdate],
|
|
97
|
+
[GatewayIntentBits.GuildPresences]: [Events.PresenceUpdate],
|
|
98
|
+
[GatewayIntentBits.GuildMessages]: [
|
|
99
|
+
Events.MessageCreate,
|
|
100
|
+
Events.MessageUpdate,
|
|
101
|
+
Events.MessageDelete,
|
|
102
|
+
Events.MessageBulkDelete
|
|
103
|
+
],
|
|
104
|
+
[GatewayIntentBits.GuildMessageReactions]: [
|
|
105
|
+
Events.MessageReactionAdd,
|
|
106
|
+
Events.MessageReactionRemove,
|
|
107
|
+
Events.MessageReactionRemoveAll,
|
|
108
|
+
Events.MessageReactionRemoveEmoji
|
|
109
|
+
],
|
|
110
|
+
[GatewayIntentBits.GuildMessageTyping]: [Events.TypingStart],
|
|
111
|
+
[GatewayIntentBits.DirectMessages]: [
|
|
112
|
+
Events.MessageCreate,
|
|
113
|
+
Events.MessageUpdate,
|
|
114
|
+
Events.MessageDelete,
|
|
115
|
+
Events.ChannelPinsUpdate
|
|
116
|
+
],
|
|
117
|
+
[GatewayIntentBits.DirectMessageReactions]: [
|
|
118
|
+
Events.MessageReactionAdd,
|
|
119
|
+
Events.MessageReactionRemove,
|
|
120
|
+
Events.MessageReactionRemoveAll,
|
|
121
|
+
Events.MessageReactionRemoveEmoji
|
|
122
|
+
],
|
|
123
|
+
[GatewayIntentBits.DirectMessageTyping]: [Events.TypingStart],
|
|
124
|
+
[GatewayIntentBits.MessageContent]: [Events.MessageCreate, Events.MessageUpdate],
|
|
125
|
+
[GatewayIntentBits.GuildScheduledEvents]: [
|
|
126
|
+
Events.GuildScheduledEventCreate,
|
|
127
|
+
Events.GuildScheduledEventDelete,
|
|
128
|
+
Events.GuildScheduledEventUpdate,
|
|
129
|
+
Events.GuildScheduledEventUserAdd,
|
|
130
|
+
Events.GuildScheduledEventUserRemove
|
|
131
|
+
],
|
|
132
|
+
[GatewayIntentBits.AutoModerationConfiguration]: [
|
|
133
|
+
Events.AutoModerationRuleCreate,
|
|
134
|
+
Events.AutoModerationRuleDelete,
|
|
135
|
+
Events.AutoModerationRuleUpdate
|
|
136
|
+
],
|
|
137
|
+
[GatewayIntentBits.AutoModerationExecution]: [Events.AutoModerationActionExecution],
|
|
138
|
+
[GatewayIntentBits.GuildMessagePolls]: [Events.MessagePollVoteAdd, Events.MessagePollVoteRemove],
|
|
139
|
+
[GatewayIntentBits.DirectMessagePolls]: [Events.MessagePollVoteAdd, Events.MessagePollVoteRemove]
|
|
140
|
+
}, EVENT_INTENT_MAPPING = {};
|
|
141
|
+
for (let [intentStr, events] of Object.entries(INTENT_GROUPS)) {
|
|
142
|
+
let intent = Number(intentStr);
|
|
143
|
+
for (let event of events)
|
|
144
|
+
EVENT_INTENT_MAPPING[event] ??= [], EVENT_INTENT_MAPPING[event].includes(intent) || EVENT_INTENT_MAPPING[event].push(intent);
|
|
57
145
|
}
|
|
58
146
|
|
|
59
|
-
// src/
|
|
60
|
-
var
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
this.canceled = true;
|
|
147
|
+
// src/lib/errors/BakitError.ts
|
|
148
|
+
var BakitError = class extends Error {
|
|
149
|
+
constructor(message) {
|
|
150
|
+
super(message), this.name = this.constructor.name, Object.setPrototypeOf(this, new.target.prototype);
|
|
64
151
|
}
|
|
65
152
|
};
|
|
66
153
|
|
|
67
|
-
// src/
|
|
68
|
-
var
|
|
69
|
-
constructor(
|
|
70
|
-
super();
|
|
71
|
-
this.
|
|
154
|
+
// src/lib/errors/ArgumentError.ts
|
|
155
|
+
var ArgumentError = class extends BakitError {
|
|
156
|
+
constructor(target, reason) {
|
|
157
|
+
super(`Invalid argument for '${target}': ${reason}`);
|
|
158
|
+
this.target = target;
|
|
159
|
+
this.reason = reason;
|
|
72
160
|
}
|
|
73
|
-
|
|
74
|
-
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// src/lib/utils/string.ts
|
|
164
|
+
function tokenize(content) {
|
|
165
|
+
let args = [], current = "", quoteChar = null, isEscaped = false;
|
|
166
|
+
for (let i = 0; i < content.length; i++) {
|
|
167
|
+
let char = content[i];
|
|
168
|
+
if (char === void 0)
|
|
169
|
+
break;
|
|
170
|
+
if (isEscaped) {
|
|
171
|
+
current += char, isEscaped = false;
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (char === "\\") {
|
|
175
|
+
isEscaped = true;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
quoteChar ? char === quoteChar ? quoteChar = null : current += char : char === '"' ? quoteChar = char : /\s/.test(char) ? current.length > 0 && (args.push(current), current = "") : current += char;
|
|
75
179
|
}
|
|
76
|
-
|
|
77
|
-
|
|
180
|
+
return current.length > 0 && args.push(current), args;
|
|
181
|
+
}
|
|
182
|
+
function extractSnowflakeId(input) {
|
|
183
|
+
if (!input) return null;
|
|
184
|
+
let mentionMatch = /^<@!?(\d{17,20})>$/.exec(input);
|
|
185
|
+
if (mentionMatch?.[1])
|
|
186
|
+
return mentionMatch[1];
|
|
187
|
+
let idMatch = /^(\d{17,20})$/.exec(input);
|
|
188
|
+
return idMatch?.[1] ? idMatch[1] : null;
|
|
189
|
+
}
|
|
190
|
+
function getTopLevelDirectory(path, entryDir) {
|
|
191
|
+
return relative(entryDir, path).split(sep)[0] ?? null;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// src/core/structures/param/Param.ts
|
|
195
|
+
var BaseParam = class {
|
|
196
|
+
constructor(options, schema) {
|
|
197
|
+
this.schema = schema;
|
|
198
|
+
let parsed = schema.parse({
|
|
199
|
+
...options,
|
|
200
|
+
description: options.description ?? options.name
|
|
201
|
+
});
|
|
202
|
+
this.options = parsed;
|
|
78
203
|
}
|
|
79
|
-
|
|
80
|
-
|
|
204
|
+
options;
|
|
205
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
206
|
+
setOption(key, value) {
|
|
207
|
+
if (value === null)
|
|
208
|
+
return delete this.options[key], this;
|
|
209
|
+
let fieldValidator = this.schema.shape[key];
|
|
210
|
+
if (!fieldValidator)
|
|
211
|
+
return this.options[key] = value, this;
|
|
212
|
+
let parsedValue = fieldValidator.parse(value);
|
|
213
|
+
return this.options[key] = parsedValue, this;
|
|
81
214
|
}
|
|
82
|
-
|
|
83
|
-
return this.
|
|
215
|
+
name(value) {
|
|
216
|
+
return this.setOption("name", value);
|
|
84
217
|
}
|
|
85
|
-
|
|
86
|
-
return this.
|
|
218
|
+
description(value) {
|
|
219
|
+
return this.setOption("description", value);
|
|
87
220
|
}
|
|
88
|
-
|
|
89
|
-
return this.
|
|
221
|
+
required(value) {
|
|
222
|
+
return this.setOption("required", value);
|
|
90
223
|
}
|
|
91
|
-
|
|
92
|
-
|
|
224
|
+
async resolve(context, value) {
|
|
225
|
+
if (context.isChatInput())
|
|
226
|
+
return await this.resolveChatInput(context);
|
|
227
|
+
if (context.isMessage()) {
|
|
228
|
+
let { required, name } = this.options;
|
|
229
|
+
if (value === void 0) {
|
|
230
|
+
if (required)
|
|
231
|
+
throw new ArgumentError(name, "is required");
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
return await this.resolveMessage(context, value);
|
|
235
|
+
}
|
|
236
|
+
throw new Error("Invalid context type provided");
|
|
93
237
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
throw new Error("Invalid source");
|
|
238
|
+
/**
|
|
239
|
+
* Helper to normalize string inputs into an options object.
|
|
240
|
+
*/
|
|
241
|
+
static getOptions(options) {
|
|
242
|
+
return typeof options == "string" ? { name: options } : options;
|
|
100
243
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (this.isMessage())
|
|
105
|
-
return this.source.author;
|
|
106
|
-
throw new Error("Invalid source");
|
|
244
|
+
}, StringParam = class extends BaseParam {
|
|
245
|
+
constructor(options) {
|
|
246
|
+
super(BaseParam.getOptions(options), StringParamSchema);
|
|
107
247
|
}
|
|
108
|
-
|
|
109
|
-
return
|
|
248
|
+
required(value) {
|
|
249
|
+
return super.required(value);
|
|
110
250
|
}
|
|
111
|
-
|
|
112
|
-
|
|
251
|
+
resolveMessage(_context, value) {
|
|
252
|
+
let { minLength, maxLength, name } = this.options;
|
|
253
|
+
if (minLength && value.length < minLength)
|
|
254
|
+
throw new ArgumentError(name, `must be at least ${minLength} chars long`);
|
|
255
|
+
if (maxLength && value.length > maxLength)
|
|
256
|
+
throw new ArgumentError(name, `must be at most ${maxLength} chars long`);
|
|
257
|
+
return value;
|
|
113
258
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
let sendOptions = {
|
|
118
|
-
...options,
|
|
119
|
-
withResponse: true
|
|
120
|
-
};
|
|
121
|
-
return this.source.deferred || this.source.replied ? await this.source.followUp(sendOptions) : (await this.source.reply(sendOptions)).resource?.message;
|
|
259
|
+
resolveChatInput(context) {
|
|
260
|
+
let { name, required } = this.options;
|
|
261
|
+
return context.source.options.getString(name, required);
|
|
122
262
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return
|
|
263
|
+
/**
|
|
264
|
+
* Sets the minimum allowed length for this string.
|
|
265
|
+
* Pass `null` to remove this constraint.
|
|
266
|
+
*/
|
|
267
|
+
min(length) {
|
|
268
|
+
return this.setOption("minLength", length);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Sets the maximum allowed length for this string.
|
|
272
|
+
* Pass `null` to remove this constraint.
|
|
273
|
+
*/
|
|
274
|
+
max(length) {
|
|
275
|
+
return this.setOption("maxLength", length);
|
|
276
|
+
}
|
|
277
|
+
}, NumberParam = class extends BaseParam {
|
|
278
|
+
constructor(options) {
|
|
279
|
+
super(BaseParam.getOptions(options), NumberParamSchema);
|
|
280
|
+
}
|
|
281
|
+
required(value) {
|
|
282
|
+
return super.required(value);
|
|
283
|
+
}
|
|
284
|
+
resolveMessage(_context, value) {
|
|
285
|
+
let { minValue, maxValue, name } = this.options, num = Number(value);
|
|
286
|
+
if (isNaN(num))
|
|
287
|
+
throw new ArgumentError(name, "must be a number");
|
|
288
|
+
if (minValue !== void 0 && num < minValue)
|
|
289
|
+
throw new ArgumentError(name, `must be greater than ${minValue}`);
|
|
290
|
+
if (maxValue !== void 0 && num > maxValue)
|
|
291
|
+
throw new ArgumentError(name, `must be less than ${minValue}`);
|
|
292
|
+
return num;
|
|
293
|
+
}
|
|
294
|
+
resolveChatInput(context) {
|
|
295
|
+
let { name, required } = this.options;
|
|
296
|
+
return context.source.options.getString(name, required);
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Sets the minimum allowed value for this number.
|
|
300
|
+
* Pass `null` to remove this constraint.
|
|
301
|
+
*/
|
|
302
|
+
min(value) {
|
|
303
|
+
return this.setOption("minValue", value);
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Sets the maximum allowed value for this number.
|
|
307
|
+
* Pass `null` to remove this constraint.
|
|
308
|
+
*/
|
|
309
|
+
max(value) {
|
|
310
|
+
return this.setOption("maxValue", value);
|
|
311
|
+
}
|
|
312
|
+
}, UserParam = class extends BaseParam {
|
|
313
|
+
constructor(options) {
|
|
314
|
+
super(BaseParam.getOptions(options), UserParamSchema);
|
|
315
|
+
}
|
|
316
|
+
required(value) {
|
|
317
|
+
return super.required(value);
|
|
318
|
+
}
|
|
319
|
+
async resolveMessage(context, value) {
|
|
320
|
+
let id = extractSnowflakeId(value);
|
|
321
|
+
if (!id)
|
|
322
|
+
return null;
|
|
323
|
+
let { users } = context.client;
|
|
324
|
+
return await users.fetch(id).catch(() => null);
|
|
325
|
+
}
|
|
326
|
+
resolveChatInput(context) {
|
|
327
|
+
let { name, required } = this.options;
|
|
328
|
+
return context.source.options.getUser(name, required);
|
|
129
329
|
}
|
|
130
330
|
};
|
|
131
|
-
var LifecycleManager = class {
|
|
331
|
+
var HookState = /* @__PURE__ */ ((HookState2) => (HookState2.Pre = "PRE", HookState2.Main = "MAIN", HookState2.Post = "POST", HookState2.Error = "ERROR", HookState2))(HookState || {}), HookOrder = /* @__PURE__ */ ((HookOrder2) => (HookOrder2[HookOrder2.First = 0] = "First", HookOrder2[HookOrder2.Last = 1] = "Last", HookOrder2))(HookOrder || {}), LifecycleManager = class {
|
|
132
332
|
constructor(id) {
|
|
133
333
|
this.id = id;
|
|
134
334
|
}
|
|
@@ -199,124 +399,123 @@ var LifecycleManager = class {
|
|
|
199
399
|
}
|
|
200
400
|
};
|
|
201
401
|
|
|
202
|
-
// src/
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
description(
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
return this.setOption("required", value);
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Helper to normalize string inputs into an options object.
|
|
223
|
-
*/
|
|
224
|
-
static getOptions(options) {
|
|
225
|
-
return typeof options == "string" ? { name: options } : options;
|
|
226
|
-
}
|
|
227
|
-
}, StringParam = class extends BaseParam {
|
|
228
|
-
constructor(options) {
|
|
229
|
-
super(BaseParam.getOptions(options));
|
|
230
|
-
}
|
|
231
|
-
required(value) {
|
|
232
|
-
return super.required(value);
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* Sets the minimum allowed length for this string.
|
|
236
|
-
* Pass `null` to remove this constraint.
|
|
237
|
-
*/
|
|
238
|
-
min(length) {
|
|
239
|
-
return this.setOption("minLength", length);
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Sets the maximum allowed length for this string.
|
|
243
|
-
* Pass `null` to remove this constraint.
|
|
244
|
-
*/
|
|
245
|
-
max(length) {
|
|
246
|
-
return this.setOption("maxLength", length);
|
|
247
|
-
}
|
|
248
|
-
}, NumberParam = class extends BaseParam {
|
|
249
|
-
constructor(options) {
|
|
250
|
-
super(BaseParam.getOptions(options));
|
|
251
|
-
}
|
|
252
|
-
required(value) {
|
|
253
|
-
return super.required(value);
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* Sets the minimum allowed value for this number.
|
|
257
|
-
* Pass `null` to remove this constraint.
|
|
258
|
-
*/
|
|
259
|
-
min(value) {
|
|
260
|
-
return this.setOption("minValue", value);
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* Sets the maximum allowed value for this number.
|
|
264
|
-
* Pass `null` to remove this constraint.
|
|
265
|
-
*/
|
|
266
|
-
max(value) {
|
|
267
|
-
return this.setOption("maxValue", value);
|
|
268
|
-
}
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
// src/command/Command.ts
|
|
272
|
-
var CommandOptionsSchema = z.object({
|
|
273
|
-
name: z.string(),
|
|
274
|
-
description: z.string().min(1).max(100).optional(),
|
|
275
|
-
params: z.array(z.instanceof(BaseParam)).default([])
|
|
402
|
+
// src/core/structures/Command.ts
|
|
403
|
+
function validateParamsOrder(params) {
|
|
404
|
+
let seenOptional = false;
|
|
405
|
+
for (let param of params)
|
|
406
|
+
if (param.options.required) {
|
|
407
|
+
if (seenOptional)
|
|
408
|
+
return false;
|
|
409
|
+
} else
|
|
410
|
+
seenOptional = true;
|
|
411
|
+
return true;
|
|
412
|
+
}
|
|
413
|
+
var CommandOptionsSchema = z4.object({
|
|
414
|
+
name: z4.string().readonly(),
|
|
415
|
+
description: z4.string().min(1).max(100).optional().readonly(),
|
|
416
|
+
nsfw: z4.boolean().default(false).readonly(),
|
|
417
|
+
params: z4.array(z4.instanceof(BaseParam)).default([]).readonly(),
|
|
418
|
+
quotes: z4.boolean().default(true).readonly()
|
|
276
419
|
}).transform((data) => ({
|
|
277
420
|
...data,
|
|
278
421
|
description: data.description ?? `Command ${data.name}`
|
|
279
|
-
}))
|
|
422
|
+
})).refine(({ params }) => validateParamsOrder(params), {
|
|
423
|
+
path: ["params"],
|
|
424
|
+
error: "Required params must be placed before optional params"
|
|
425
|
+
}), Command = class extends LifecycleManager {
|
|
280
426
|
constructor(options) {
|
|
281
427
|
let _options = CommandOptionsSchema.parse(typeof options == "string" ? { name: options } : options);
|
|
282
|
-
super(`command:${_options.name}`), this.options = _options
|
|
428
|
+
super(`command:${_options.name}`), this.options = _options, this.setHook("syntaxError", "ERROR" /* Error */, async (ctx, error, ...args) => {
|
|
429
|
+
await this.handleSyntaxError(ctx, error, args);
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
async handleSyntaxError(context, error, _args) {
|
|
433
|
+
error instanceof BakitError && await context.send(error.message);
|
|
434
|
+
}
|
|
435
|
+
toSlashCommandJSON() {
|
|
436
|
+
let { name, description, nsfw, params } = this.options, builder = new SlashCommandBuilder().setName(name).setDescription(description).setNSFW(nsfw);
|
|
437
|
+
return this.initSlashCommandOptions(builder, params), builder.toJSON();
|
|
438
|
+
}
|
|
439
|
+
initSlashCommandOptions(builder, params) {
|
|
440
|
+
for (let param of params)
|
|
441
|
+
this.initSlashCommandOption(builder, param);
|
|
442
|
+
}
|
|
443
|
+
initSlashCommandOption(builder, param) {
|
|
444
|
+
let initOption = (builder2) => {
|
|
445
|
+
let { name, description, required } = param.options;
|
|
446
|
+
return builder2.setName(name).setDescription(description).setRequired(required);
|
|
447
|
+
};
|
|
448
|
+
if (param instanceof StringParam) {
|
|
449
|
+
let { maxLength, minLength } = param.options, option = initOption(new SlashCommandStringOption());
|
|
450
|
+
maxLength && option.setMaxLength(maxLength), minLength && option.setMinLength(minLength), builder.addStringOption(option);
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
if (param instanceof NumberParam) {
|
|
454
|
+
let { maxValue, minValue } = param.options, option = initOption(new SlashCommandNumberOption());
|
|
455
|
+
maxValue && option.setMaxValue(maxValue), minValue && option.setMinValue(minValue), builder.addNumberOption(option);
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
if (param instanceof UserParam) {
|
|
459
|
+
let option = initOption(new SlashCommandUserOption());
|
|
460
|
+
builder.addUserOption(option);
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
283
463
|
}
|
|
284
464
|
};
|
|
285
465
|
function defineCommand(options) {
|
|
286
466
|
return new Command(options);
|
|
287
467
|
}
|
|
288
468
|
|
|
289
|
-
// src/
|
|
469
|
+
// src/core/managers/BaseClientManager.ts
|
|
290
470
|
var BaseClientManager = class {
|
|
291
471
|
constructor(client) {
|
|
292
472
|
this.client = client;
|
|
293
473
|
}
|
|
294
474
|
};
|
|
295
|
-
|
|
296
|
-
// src/command/CommandManager.ts
|
|
297
475
|
var CommandManager = class extends BaseClientManager {
|
|
298
476
|
commands = new Collection();
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
try {
|
|
304
|
-
let { default: command } = await import(pathToFileURL(file).toString());
|
|
305
|
-
if (!command) {
|
|
306
|
-
console.warn(`[Loader] File has no default export: ${file}`);
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
if (!(command instanceof Command)) {
|
|
310
|
-
console.warn(`[Loader] Default export is not a Command: ${file}`);
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
return this.add(command), command;
|
|
314
|
-
} catch (error) {
|
|
315
|
-
console.error(`An error occurred while trying to add command for '${file}':`, error);
|
|
316
|
-
}
|
|
317
|
-
}), loaded = (await Promise.all(loads)).filter((x) => x !== void 0);
|
|
318
|
-
return console.log(`Loaded ${loaded.length} command(s).`), loaded;
|
|
477
|
+
entries = new Collection();
|
|
478
|
+
async loadModules(entryDir) {
|
|
479
|
+
let pattern = posix.join(posix.resolve(entryDir), "commands", "**/*.{ts,js}"), files = await glob(pattern, { cwd: process.cwd(), absolute: true }), filtered = (await Promise.all(files.map((file) => this.load(file)))).filter((c) => !!c);
|
|
480
|
+
return console.log(`[Loader] Loaded ${filtered.length}/${files.length} command(s)`), filtered;
|
|
319
481
|
}
|
|
482
|
+
/**
|
|
483
|
+
* Load the file and add the command to the registry.
|
|
484
|
+
* @param path The path to the command file.
|
|
485
|
+
* @returns The command object if added successfully.
|
|
486
|
+
*/
|
|
487
|
+
async load(path) {
|
|
488
|
+
let command = (await import(pathToFileURL(path).href)).default;
|
|
489
|
+
if (!command) {
|
|
490
|
+
console.warn(`[Loader] File has no default export: ${path}`);
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
if (!(command instanceof Command)) {
|
|
494
|
+
console.warn(`[Loader] Default export is not a Command: ${path}`);
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
return this.add(command), this.entries.set(path, command), command;
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Unload the file and remove the command from the registry.
|
|
501
|
+
* @param path The path to the command file.
|
|
502
|
+
* @returns The command object if unloaded successfully.
|
|
503
|
+
*/
|
|
504
|
+
async unload(path) {
|
|
505
|
+
let command = this.entries.get(path);
|
|
506
|
+
if (this.entries.delete(path), (await Promise.resolve().then(() => (init_register(), register_exports))).unload(path), !!command)
|
|
507
|
+
return this.remove(command);
|
|
508
|
+
}
|
|
509
|
+
async reload(path) {
|
|
510
|
+
await this.unload(path);
|
|
511
|
+
let command = await this.load(path);
|
|
512
|
+
if (command)
|
|
513
|
+
return console.log(`[Loader] Reloaded command '${command.options.name}' at '${path}'`), command;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Add a command to the registry.
|
|
517
|
+
* @param command Command to add.
|
|
518
|
+
*/
|
|
320
519
|
add(command) {
|
|
321
520
|
if (!(command instanceof Command))
|
|
322
521
|
throw new Error("Invalid command provided");
|
|
@@ -327,65 +526,106 @@ var CommandManager = class extends BaseClientManager {
|
|
|
327
526
|
}
|
|
328
527
|
this.commands.set(name, command);
|
|
329
528
|
}
|
|
529
|
+
/**
|
|
530
|
+
* Remove a command from the registry.
|
|
531
|
+
* @param target Command name or object to remove.
|
|
532
|
+
* @returns The command object if removed successfully.
|
|
533
|
+
*/
|
|
330
534
|
remove(target) {
|
|
535
|
+
if (typeof target != "string" && !(target instanceof Command))
|
|
536
|
+
return;
|
|
331
537
|
let name = typeof target == "string" ? target : target.options.name, existing = this.commands.get(name);
|
|
332
538
|
if (existing)
|
|
333
539
|
return this.commands.delete(name), existing;
|
|
334
540
|
}
|
|
541
|
+
/**
|
|
542
|
+
* Get a command using its name.
|
|
543
|
+
* @param name The command to get.
|
|
544
|
+
* @returns The command object.
|
|
545
|
+
*/
|
|
335
546
|
get(name) {
|
|
336
547
|
return this.commands.get(name);
|
|
337
548
|
}
|
|
338
549
|
};
|
|
339
|
-
var ListenerOptionsSchema =
|
|
340
|
-
name:
|
|
341
|
-
once:
|
|
550
|
+
var ListenerOptionsSchema = z4.object({
|
|
551
|
+
name: z4.enum(Events),
|
|
552
|
+
once: z4.boolean().default(false)
|
|
342
553
|
}), Listener = class extends LifecycleManager {
|
|
343
554
|
options;
|
|
344
555
|
constructor(options) {
|
|
345
556
|
let _options = ListenerOptionsSchema.parse(typeof options == "string" ? { name: options } : options);
|
|
346
|
-
super(`listener:${_options.name}`), this.options =
|
|
557
|
+
super(`listener:${_options.name}`), this.options = _options;
|
|
347
558
|
}
|
|
348
559
|
};
|
|
349
560
|
function defineListener(options) {
|
|
350
561
|
return new Listener(options);
|
|
351
562
|
}
|
|
352
563
|
|
|
353
|
-
// src/
|
|
564
|
+
// src/core/context/Context.ts
|
|
565
|
+
var Context = class {
|
|
566
|
+
canceled = false;
|
|
567
|
+
cancel() {
|
|
568
|
+
this.canceled = true;
|
|
569
|
+
}
|
|
570
|
+
};
|
|
354
571
|
var ListenerManager = class extends BaseClientManager {
|
|
355
572
|
listeners = [];
|
|
356
|
-
|
|
573
|
+
entries = new Collection();
|
|
357
574
|
executors = /* @__PURE__ */ new WeakMap();
|
|
358
|
-
async loadModules() {
|
|
359
|
-
let
|
|
360
|
-
|
|
361
|
-
})).map(async (file) => {
|
|
362
|
-
try {
|
|
363
|
-
let { default: listener } = await import(pathToFileURL(file).toString());
|
|
364
|
-
if (!listener) {
|
|
365
|
-
console.warn(`[Loader] File has no default export: ${file}`);
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
if (!(listener instanceof Listener)) {
|
|
369
|
-
console.warn(`[Loader] Default export is not a Listener: ${file}`);
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
|
-
return this.add(listener), listener;
|
|
373
|
-
} catch (error) {
|
|
374
|
-
console.error(`An error occurred while trying to add listener for '${file}':`, error);
|
|
375
|
-
}
|
|
376
|
-
}), loaded = (await Promise.all(loads)).filter((x) => x !== void 0);
|
|
377
|
-
return console.log(`Loaded ${loaded.length} listener(s).`), loaded;
|
|
575
|
+
async loadModules(entryDir) {
|
|
576
|
+
let pattern = posix.join(posix.resolve(entryDir), "listeners", "**/*.{ts,js}"), files = await glob(pattern, { cwd: process.cwd(), absolute: true }), filtered = (await Promise.all(files.map((file) => this.load(file)))).filter((l) => !!l);
|
|
577
|
+
return console.log(`[Loader] Loaded ${filtered.length}/${files.length} listener(s)`), filtered;
|
|
378
578
|
}
|
|
579
|
+
/**
|
|
580
|
+
* Load the file and add the listener to the registry.
|
|
581
|
+
* @param path The path to the listener file.
|
|
582
|
+
* @returns The listener object if added successfully.
|
|
583
|
+
*/
|
|
584
|
+
async load(path) {
|
|
585
|
+
let listener = (await import(pathToFileURL(path).href)).default;
|
|
586
|
+
if (!listener) {
|
|
587
|
+
console.warn(`[Loader] File has no default export: ${path}`);
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
if (!(listener instanceof Listener)) {
|
|
591
|
+
console.warn(`[Loader] Default export is not a Listener: ${path}`);
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
return this.add(listener), this.entries.set(path, listener), listener;
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Unload the file and remove the listener from the registry.
|
|
598
|
+
* @param path The path to the listener file.
|
|
599
|
+
* @returns The listener object if unloaded successfully.
|
|
600
|
+
*/
|
|
601
|
+
async unload(path) {
|
|
602
|
+
let listener = this.entries.get(path);
|
|
603
|
+
if (this.entries.delete(path), (await Promise.resolve().then(() => (init_register(), register_exports))).unload(path), !!listener)
|
|
604
|
+
return this.remove(listener)?.[0];
|
|
605
|
+
}
|
|
606
|
+
async reload(path) {
|
|
607
|
+
await this.unload(path);
|
|
608
|
+
let listener = await this.load(path);
|
|
609
|
+
if (listener)
|
|
610
|
+
return console.log(`[Loader] Reloaded listener '${listener.options.name}' at '${path}'`), listener;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Add a listener to the registry and create a listener for client.
|
|
614
|
+
* @param listener Listener to add.
|
|
615
|
+
*/
|
|
379
616
|
add(listener) {
|
|
380
617
|
if (!(listener instanceof Listener))
|
|
381
618
|
throw new Error("Invalid listener provided");
|
|
382
|
-
let execute = (...args) => {
|
|
619
|
+
let { once, name } = listener.options, execute = (...args) => {
|
|
383
620
|
listener.execute(new Context(), ...args);
|
|
384
621
|
};
|
|
385
|
-
this.listeners.push(listener), this.executors.set(listener, execute);
|
|
386
|
-
let { once, name } = listener.options;
|
|
387
|
-
this.client[once ? "once" : "on"](name, execute);
|
|
622
|
+
this.listeners.push(listener), this.executors.set(listener, execute), this.client[once ? "once" : "on"](name, execute);
|
|
388
623
|
}
|
|
624
|
+
/**
|
|
625
|
+
* Remove a listener from the registry and client.
|
|
626
|
+
* @param target Listener name or object to remove.
|
|
627
|
+
* @returns The list of listener objects if removed successfully.
|
|
628
|
+
*/
|
|
389
629
|
remove(target) {
|
|
390
630
|
let isMatched = (listener) => typeof target == "string" ? listener.options.name === target : listener === target, removed = [];
|
|
391
631
|
return this.listeners = this.listeners.filter((listener) => {
|
|
@@ -396,21 +636,38 @@ var ListenerManager = class extends BaseClientManager {
|
|
|
396
636
|
return execute && (this.client.removeListener(listener.options.name, execute), this.executors.delete(listener)), false;
|
|
397
637
|
}), removed;
|
|
398
638
|
}
|
|
639
|
+
/**
|
|
640
|
+
* Get a list of required intents for Bakit to run correctly.
|
|
641
|
+
* @returns Used intents.
|
|
642
|
+
*/
|
|
643
|
+
getBaseIntents() {
|
|
644
|
+
return new IntentsBitField([GatewayIntentBits.Guilds]);
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Get a list of needed intents based on registered listeners to receive needed events.
|
|
648
|
+
* @returns Used intents.
|
|
649
|
+
*/
|
|
650
|
+
getNeededIntents() {
|
|
651
|
+
let result = this.getBaseIntents();
|
|
652
|
+
for (let listener of this.listeners) {
|
|
653
|
+
let eventName = listener.options.name, requiredIntents = EVENT_INTENT_MAPPING[eventName];
|
|
654
|
+
requiredIntents && result.add(requiredIntents);
|
|
655
|
+
}
|
|
656
|
+
return result;
|
|
657
|
+
}
|
|
399
658
|
};
|
|
400
659
|
|
|
401
|
-
// src/BakitClient.ts
|
|
402
|
-
var
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
660
|
+
// src/core/client/BakitClient.ts
|
|
661
|
+
var BakitClient = class extends Client {
|
|
662
|
+
constructor(options, instance) {
|
|
663
|
+
super(options);
|
|
664
|
+
this.instance = instance;
|
|
665
|
+
this.managers = {
|
|
406
666
|
commands: new CommandManager(this),
|
|
407
667
|
listeners: new ListenerManager(this)
|
|
408
668
|
};
|
|
409
669
|
}
|
|
410
|
-
|
|
411
|
-
let { commands, listeners } = this.managers;
|
|
412
|
-
return await Promise.all([commands.loadModules(), listeners.loadModules()]), await this.login(token);
|
|
413
|
-
}
|
|
670
|
+
managers;
|
|
414
671
|
/**
|
|
415
672
|
* Check if the client is connected to gateway successfully and finished initialization.
|
|
416
673
|
*/
|
|
@@ -443,25 +700,263 @@ var BakitClient3 = class extends Client {
|
|
|
443
700
|
return `${this.constructor.name} {}`;
|
|
444
701
|
}
|
|
445
702
|
};
|
|
446
|
-
var
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
|
|
703
|
+
var BaseCommandContext = class extends Context {
|
|
704
|
+
constructor(source) {
|
|
705
|
+
super();
|
|
706
|
+
this.source = source;
|
|
707
|
+
}
|
|
708
|
+
get client() {
|
|
709
|
+
return this.source.client;
|
|
710
|
+
}
|
|
711
|
+
get channel() {
|
|
712
|
+
return this.source.channel;
|
|
713
|
+
}
|
|
714
|
+
get channelId() {
|
|
715
|
+
return this.source.channelId;
|
|
716
|
+
}
|
|
717
|
+
get guild() {
|
|
718
|
+
return this.source.guild;
|
|
719
|
+
}
|
|
720
|
+
get guildId() {
|
|
721
|
+
return this.source.guildId;
|
|
722
|
+
}
|
|
723
|
+
get member() {
|
|
724
|
+
return this.source.member;
|
|
725
|
+
}
|
|
726
|
+
inGuild() {
|
|
727
|
+
return !!this.guildId;
|
|
728
|
+
}
|
|
729
|
+
inCachedGuild() {
|
|
730
|
+
if (this.isChatInput())
|
|
731
|
+
return this.source.inCachedGuild();
|
|
732
|
+
if (this.isMessage())
|
|
733
|
+
return this.source.inGuild();
|
|
734
|
+
throw new Error("Invalid source");
|
|
735
|
+
}
|
|
736
|
+
get user() {
|
|
737
|
+
if (this.isChatInput())
|
|
738
|
+
return this.source.user;
|
|
739
|
+
if (this.isMessage())
|
|
740
|
+
return this.source.author;
|
|
741
|
+
throw new Error("Invalid source");
|
|
742
|
+
}
|
|
743
|
+
isChatInput() {
|
|
744
|
+
return this.source instanceof ChatInputCommandInteraction;
|
|
745
|
+
}
|
|
746
|
+
isMessage() {
|
|
747
|
+
return this.source instanceof Message;
|
|
748
|
+
}
|
|
749
|
+
}, ChatInputContext = class extends BaseCommandContext {
|
|
750
|
+
async send(options) {
|
|
751
|
+
typeof options == "string" && (options = { content: options });
|
|
752
|
+
let sendOptions = {
|
|
753
|
+
...options,
|
|
754
|
+
withResponse: true
|
|
755
|
+
};
|
|
756
|
+
return this.source.deferred || this.source.replied ? await this.source.followUp(sendOptions) : (await this.source.reply(sendOptions)).resource?.message;
|
|
757
|
+
}
|
|
758
|
+
}, MessageContext = class extends BaseCommandContext {
|
|
759
|
+
async send(options) {
|
|
760
|
+
let { channel } = this;
|
|
761
|
+
if (!channel?.isSendable())
|
|
762
|
+
throw new Error("Invalid channel or channel is not sendable");
|
|
763
|
+
return await channel.send(options);
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
var ProjectConfigSchema = z4.object({
|
|
767
|
+
/**
|
|
768
|
+
* The gateway intents to use for the Discord client.
|
|
769
|
+
*
|
|
770
|
+
* - `auto` — automatically determine the required intents.
|
|
771
|
+
* - bigint — a raw bitfield value representing the combined intents.
|
|
772
|
+
* - array — a list of individual intent flags from `GatewayIntentBits`.
|
|
773
|
+
*
|
|
774
|
+
* @defaultvalue `auto`
|
|
775
|
+
*/
|
|
776
|
+
intents: z4.union([z4.literal("auto"), z4.bigint(), z4.array(z4.enum(GatewayIntentBits))]).default("auto"),
|
|
777
|
+
/**
|
|
778
|
+
* Optional custom client options for Discord.js (excluding `intents`).
|
|
779
|
+
*
|
|
780
|
+
* These are passed directly to the `Client` constructor when initializing the bot.
|
|
781
|
+
*
|
|
782
|
+
* @see {@link https://discord.js.org/docs/packages/discord.js/main/ClientOptions:Interface}
|
|
783
|
+
*/
|
|
784
|
+
clientOptions: z4.custom().optional(),
|
|
785
|
+
prefixes: z4.array(z4.string()).default([]),
|
|
786
|
+
token: z4.string()
|
|
456
787
|
});
|
|
788
|
+
function defineConfig(config) {
|
|
789
|
+
return config;
|
|
790
|
+
}
|
|
791
|
+
var _config;
|
|
792
|
+
async function loadConfig(cwd = process.cwd()) {
|
|
793
|
+
if (_config)
|
|
794
|
+
return console.warn("loadConfig() was called more than once. This shouldn't happen."), _config;
|
|
795
|
+
let globPattern = `bakit.config.{${["ts", "js"].join(",")}}`, [configPath, other] = await glob(globPattern, {
|
|
796
|
+
cwd: cwd.replace(/\\/g, "/"),
|
|
797
|
+
// ensure the path uses `/` instead of `\` on Windows
|
|
798
|
+
absolute: true
|
|
799
|
+
});
|
|
800
|
+
if (!configPath)
|
|
801
|
+
throw new Error("Missing config file");
|
|
802
|
+
other && console.warn(`Multiple config files found in ${cwd}. Using ${configPath}.`);
|
|
803
|
+
let config = (await import(pathToFileURL(configPath).href)).default;
|
|
804
|
+
return _config = Object.freeze(await ProjectConfigSchema.parseAsync(config)), _config;
|
|
805
|
+
}
|
|
806
|
+
function getConfig() {
|
|
807
|
+
if (!_config)
|
|
808
|
+
throw new Error("Project config is not loaded.");
|
|
809
|
+
return _config;
|
|
810
|
+
}
|
|
811
|
+
var messageCommandHandler = defineListener(Events.MessageCreate), chatInputCommandHandler = defineListener(Events.InteractionCreate), registerCommandsHandler = defineListener({
|
|
812
|
+
name: Events.ClientReady,
|
|
813
|
+
once: true
|
|
814
|
+
});
|
|
815
|
+
registerCommandsHandler.main(async (_, client) => {
|
|
816
|
+
let { managers, instance } = client, { commands } = managers, { cache } = instance, payload = commands.commands.map((cmd) => cmd.toSlashCommandJSON()).sort((a, b) => a.name.localeCompare(b.name)), currentHash = cache.getHash(payload), CACHE_KEY = "commands/meta.json", cachedMeta = await cache.read(CACHE_KEY);
|
|
817
|
+
if (cachedMeta && cachedMeta.hash === currentHash) {
|
|
818
|
+
let { timestamp, count } = cachedMeta, time = new Date(timestamp).toLocaleString();
|
|
819
|
+
console.log(`${count} command(s) are up to date (Last sync: ${time}). Skipping registration.`);
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
try {
|
|
823
|
+
let result = await client.application.commands.set(payload);
|
|
824
|
+
cache.write(CACHE_KEY, {
|
|
825
|
+
hash: currentHash,
|
|
826
|
+
timestamp: Date.now(),
|
|
827
|
+
count: result.size
|
|
828
|
+
}), cache.write("commands/debug_dump.json", payload), console.log(`Registered ${result.size} application command(s).`);
|
|
829
|
+
} catch (error) {
|
|
830
|
+
console.error("Failed to register commands:", error);
|
|
831
|
+
}
|
|
832
|
+
});
|
|
833
|
+
messageCommandHandler.main(async (_, message) => {
|
|
834
|
+
let config = getConfig();
|
|
835
|
+
if (message.author.bot)
|
|
836
|
+
return;
|
|
837
|
+
let { content } = message, client = message.client, lowerContent = content.toLowerCase(), prefix = config.prefixes.find((p) => lowerContent.startsWith(p));
|
|
838
|
+
if (!prefix)
|
|
839
|
+
return;
|
|
840
|
+
let [name, ...args] = content.slice(prefix.length).trim().split(/\s+/g);
|
|
841
|
+
if (!name)
|
|
842
|
+
return;
|
|
843
|
+
let command = client.managers.commands.get(name);
|
|
844
|
+
if (!command)
|
|
845
|
+
return;
|
|
846
|
+
let context = new MessageContext(message), { params, quotes } = command.options, rawArgs = quotes ? tokenize(args.join(" ")) : args, resolvedArgs = [];
|
|
847
|
+
for (let i = 0; i < params.length; i++) {
|
|
848
|
+
let param = params[i], arg = rawArgs[i];
|
|
849
|
+
if (!param)
|
|
850
|
+
break;
|
|
851
|
+
let resolved = await param.resolve(context, arg);
|
|
852
|
+
resolvedArgs.push(resolved);
|
|
853
|
+
}
|
|
854
|
+
await command.execute(context, ...resolvedArgs);
|
|
855
|
+
});
|
|
856
|
+
chatInputCommandHandler.main(async (_, interaction) => {
|
|
857
|
+
if (!interaction.isChatInputCommand())
|
|
858
|
+
return;
|
|
859
|
+
let { commandName } = interaction, command = interaction.client.managers.commands.get(commandName);
|
|
860
|
+
if (!command)
|
|
861
|
+
return;
|
|
862
|
+
let context = new ChatInputContext(interaction), { params } = command.options, resolvedArgs = [];
|
|
863
|
+
for (let param of params) {
|
|
864
|
+
let resolved = await param.resolve(context);
|
|
865
|
+
resolvedArgs.push(resolved);
|
|
866
|
+
}
|
|
867
|
+
await command.execute(context, ...resolvedArgs);
|
|
868
|
+
});
|
|
869
|
+
var ProjectCacheManager = class {
|
|
870
|
+
rootDir;
|
|
871
|
+
constructor(root = process.cwd()) {
|
|
872
|
+
this.rootDir = join(root, ".bakit"), this.ensureRoot();
|
|
873
|
+
}
|
|
874
|
+
ensureRoot() {
|
|
875
|
+
existsSync(this.rootDir) || mkdirSync(this.rootDir, { recursive: true });
|
|
876
|
+
}
|
|
877
|
+
getHash(data) {
|
|
878
|
+
return createHash("sha256").update(JSON.stringify(data)).digest("hex");
|
|
879
|
+
}
|
|
880
|
+
async write(path, data) {
|
|
881
|
+
let fullPath = join(this.rootDir, path), dir = dirname(fullPath);
|
|
882
|
+
await mkdir(dir, { recursive: true });
|
|
883
|
+
let content = typeof data == "string" ? data : JSON.stringify(data);
|
|
884
|
+
await writeFile(fullPath, content, "utf-8");
|
|
885
|
+
}
|
|
886
|
+
async read(path) {
|
|
887
|
+
let fullPath = join(this.rootDir, path);
|
|
888
|
+
try {
|
|
889
|
+
let content = await readFile(fullPath, "utf-8");
|
|
890
|
+
return JSON.parse(content);
|
|
891
|
+
} catch {
|
|
892
|
+
return null;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
async clear() {
|
|
896
|
+
await rm(this.rootDir, { recursive: true, force: true });
|
|
897
|
+
}
|
|
898
|
+
clearSync() {
|
|
899
|
+
existsSync(this.rootDir) && rmSync(this.rootDir, { recursive: true, force: true });
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
|
|
903
|
+
// src/core/internal/Instance.ts
|
|
904
|
+
var Instance = class {
|
|
905
|
+
client;
|
|
906
|
+
cache;
|
|
907
|
+
constructor() {
|
|
908
|
+
this.cache = new ProjectCacheManager();
|
|
909
|
+
}
|
|
910
|
+
async start() {
|
|
911
|
+
await loadConfig();
|
|
912
|
+
let config = getConfig();
|
|
913
|
+
this.client = new BakitClient(
|
|
914
|
+
{
|
|
915
|
+
intents: [],
|
|
916
|
+
...config.clientOptions
|
|
917
|
+
},
|
|
918
|
+
this
|
|
919
|
+
), await this.loadModules(), this.initIntents(), await this.client.login(config.token), this.initProcess();
|
|
920
|
+
}
|
|
921
|
+
initProcess() {
|
|
922
|
+
process.on("message", (msg) => this.onProcessMessage(msg));
|
|
923
|
+
}
|
|
924
|
+
loadModules() {
|
|
925
|
+
let { managers } = this.client, { commands, listeners } = managers;
|
|
926
|
+
return listeners.add(chatInputCommandHandler), listeners.add(messageCommandHandler), listeners.add(registerCommandsHandler), Promise.all([commands.loadModules("src"), listeners.loadModules("src")]);
|
|
927
|
+
}
|
|
928
|
+
initIntents() {
|
|
929
|
+
let config = getConfig(), { options, managers } = this.client, { listeners } = managers, intents;
|
|
930
|
+
config.intents === "auto" ? intents = listeners.getNeededIntents() : (intents = listeners.getBaseIntents(), typeof config.intents == "bigint" ? intents.bitfield = Number(config.intents) : intents.add(...config.intents)), options.intents = intents;
|
|
931
|
+
}
|
|
932
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
933
|
+
async onProcessMessage(message) {
|
|
934
|
+
let { type, file } = message;
|
|
935
|
+
if (!type.startsWith("hmr:"))
|
|
936
|
+
return;
|
|
937
|
+
let target = type.split(":")[1], { listeners, commands } = this.client.managers;
|
|
938
|
+
switch (target) {
|
|
939
|
+
case "listeners":
|
|
940
|
+
await listeners.reload(file);
|
|
941
|
+
break;
|
|
942
|
+
case "commands":
|
|
943
|
+
await commands.reload(file);
|
|
944
|
+
break;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
};
|
|
948
|
+
function useApp() {
|
|
949
|
+
return new Instance();
|
|
950
|
+
}
|
|
457
951
|
|
|
458
|
-
// src/
|
|
952
|
+
// src/core/structures/param/Params.ts
|
|
459
953
|
function createFactory(ctor) {
|
|
460
954
|
return (...args) => new ctor(...args);
|
|
461
955
|
}
|
|
462
956
|
var Params = {
|
|
463
957
|
string: createFactory(StringParam),
|
|
464
|
-
number: createFactory(NumberParam)
|
|
958
|
+
number: createFactory(NumberParam),
|
|
959
|
+
user: createFactory(UserParam)
|
|
465
960
|
};
|
|
466
961
|
|
|
467
|
-
export {
|
|
962
|
+
export { ArgumentError, BakitClient, BakitError, BaseClientManager, BaseCommandContext, BaseParam, BaseParamSchema, ChatInputContext, Command, CommandManager, CommandOptionsSchema, Context, EVENT_INTENT_MAPPING, HookOrder, HookState, Instance, LifecycleManager, Listener, ListenerManager, ListenerOptionsSchema, MessageContext, NumberParam, NumberParamSchema, ParamUserType, Params, ProjectCacheManager, ProjectConfigSchema, StringParam, StringParamSchema, UserParam, UserParamSchema, chatInputCommandHandler, defineCommand, defineConfig, defineListener, extractSnowflakeId, getConfig, getTopLevelDirectory, loadConfig, messageCommandHandler, registerCommandsHandler, tokenize, useApp, validateParamsOrder };
|