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