bakit 2.0.0-alpha.11 → 2.0.0-alpha.13
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/bin/bakit.js +111 -0
- package/dist/index.d.ts +94 -11
- package/dist/index.js +230 -80
- package/package.json +3 -2
- package/bin/bakit.js +0 -39
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { config } from 'dotenv';
|
|
2
|
+
import { program } from 'commander';
|
|
3
|
+
import { fork } from 'child_process';
|
|
4
|
+
import chokidar from 'chokidar';
|
|
5
|
+
import path, { relative, sep } from 'path';
|
|
6
|
+
import { createJiti } from 'jiti';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
|
|
9
|
+
// src/bin/bakit.ts
|
|
10
|
+
var Module = class {
|
|
11
|
+
static jiti = createJiti(process.cwd());
|
|
12
|
+
static async import(module, defaultImport = false) {
|
|
13
|
+
let path2 = this.resolve(module);
|
|
14
|
+
if (!path2)
|
|
15
|
+
return null;
|
|
16
|
+
try {
|
|
17
|
+
return await this.jiti.import(path2, { default: defaultImport });
|
|
18
|
+
} catch (error) {
|
|
19
|
+
return console.error(`[Module] Import failed for ${path2}:`, error), null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
static isLoaded(module) {
|
|
23
|
+
let path2 = this.resolve(module);
|
|
24
|
+
return !!path2 && !!this.jiti.cache[path2];
|
|
25
|
+
}
|
|
26
|
+
static unload(module) {
|
|
27
|
+
let path2 = this.resolve(module);
|
|
28
|
+
return !path2 || !this.jiti.cache[path2] ? false : (delete this.jiti.cache[path2], true);
|
|
29
|
+
}
|
|
30
|
+
static resolve(module) {
|
|
31
|
+
try {
|
|
32
|
+
let url = this.jiti.esmResolve(module);
|
|
33
|
+
return fileURLToPath(url);
|
|
34
|
+
} catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
static getTopLevel(path2, entryDir) {
|
|
39
|
+
return relative(entryDir, path2).split(sep)[0] ?? null;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// src/base/process/DevProcessManager.ts
|
|
44
|
+
var DevProcessManager = class {
|
|
45
|
+
constructor(options) {
|
|
46
|
+
this.options = options;
|
|
47
|
+
}
|
|
48
|
+
child = null;
|
|
49
|
+
restartTimer = null;
|
|
50
|
+
start() {
|
|
51
|
+
console.log("Starting bakit in dev mode..."), this.startChild(), this.startWatcher();
|
|
52
|
+
}
|
|
53
|
+
startChild() {
|
|
54
|
+
if (this.child) return;
|
|
55
|
+
let entry = path.resolve(this.options.entry);
|
|
56
|
+
this.child = fork(entry, {
|
|
57
|
+
execArgv: ["--import", "tsx"],
|
|
58
|
+
stdio: "inherit",
|
|
59
|
+
env: {
|
|
60
|
+
...process.env,
|
|
61
|
+
NODE_ENV: "development"
|
|
62
|
+
}
|
|
63
|
+
}), this.child.on("exit", () => {
|
|
64
|
+
this.child = null;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
restartChild() {
|
|
68
|
+
if (!this.child)
|
|
69
|
+
return this.startChild();
|
|
70
|
+
let old = this.child;
|
|
71
|
+
old.once("exit", () => {
|
|
72
|
+
this.child = null, this.startChild();
|
|
73
|
+
}), old.kill("SIGTERM");
|
|
74
|
+
}
|
|
75
|
+
startWatcher() {
|
|
76
|
+
let { rootDir } = this.options;
|
|
77
|
+
chokidar.watch(rootDir, {
|
|
78
|
+
ignoreInitial: true,
|
|
79
|
+
awaitWriteFinish: {
|
|
80
|
+
stabilityThreshold: 200,
|
|
81
|
+
pollInterval: 50
|
|
82
|
+
}
|
|
83
|
+
}).on("change", (file) => this.onFileChanged(file));
|
|
84
|
+
}
|
|
85
|
+
onFileChanged(file) {
|
|
86
|
+
if (!this.child)
|
|
87
|
+
return;
|
|
88
|
+
let top = Module.getTopLevel(file, this.options.rootDir);
|
|
89
|
+
if (top && this.options.hotDirs.includes(top)) {
|
|
90
|
+
this.child.connected && this.child.send({ type: `hmr:${top}`, file });
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
this.scheduleRestart();
|
|
94
|
+
}
|
|
95
|
+
scheduleRestart() {
|
|
96
|
+
this.restartTimer && clearTimeout(this.restartTimer), this.restartTimer = setTimeout(() => {
|
|
97
|
+
console.log("Detected changes, restarting..."), this.restartChild(), this.restartTimer = null;
|
|
98
|
+
}, 150);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// src/bin/bakit.ts
|
|
103
|
+
program.name("bakit");
|
|
104
|
+
program.command("dev").action(() => {
|
|
105
|
+
config({ path: [".env.local", ".env"], quiet: true }), new DevProcessManager({
|
|
106
|
+
rootDir: "src",
|
|
107
|
+
entry: "src/index.ts",
|
|
108
|
+
hotDirs: ["commands", "listeners"]
|
|
109
|
+
}).start();
|
|
110
|
+
});
|
|
111
|
+
program.parse();
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as discord_js from 'discord.js';
|
|
2
|
-
import { GatewayIntentBits, ClientOptions, ChatInputCommandInteraction, CacheType, Message, User, MessageCreateOptions, InteractionReplyOptions, Awaitable, Collection, Events, IntentsBitField,
|
|
2
|
+
import { GatewayIntentBits, ClientOptions, ChatInputCommandInteraction, CacheType, Message, User, MessageCreateOptions, InteractionReplyOptions, Awaitable, Collection, Events, IntentsBitField, ClientEvents, Client } from 'discord.js';
|
|
3
3
|
import z$1, { z } from 'zod';
|
|
4
4
|
import * as jiti from 'jiti';
|
|
5
5
|
import { inspect } from 'node:util';
|
|
@@ -7,7 +7,6 @@ import { inspect } from 'node:util';
|
|
|
7
7
|
declare const ProjectConfigSchema: z.ZodObject<{
|
|
8
8
|
intents: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<"auto">, z.ZodBigInt, z.ZodArray<z.ZodEnum<typeof GatewayIntentBits>>]>>;
|
|
9
9
|
clientOptions: z.ZodOptional<z.ZodCustom<Omit<ClientOptions, "intents">, Omit<ClientOptions, "intents">>>;
|
|
10
|
-
entryDir: z.ZodDefault<z.ZodString>;
|
|
11
10
|
prefixes: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
12
11
|
token: z.ZodString;
|
|
13
12
|
}, z.core.$strip>;
|
|
@@ -41,7 +40,14 @@ declare function tokenize(content: string): string[];
|
|
|
41
40
|
*/
|
|
42
41
|
declare function extractSnowflakeId(input: string): string | null;
|
|
43
42
|
|
|
44
|
-
declare
|
|
43
|
+
declare class Module {
|
|
44
|
+
static jiti: jiti.Jiti;
|
|
45
|
+
static import<T>(module: string, defaultImport?: boolean): Promise<T | null>;
|
|
46
|
+
static isLoaded(module: string): boolean;
|
|
47
|
+
static unload(module: string): boolean;
|
|
48
|
+
static resolve(module: string): string | null;
|
|
49
|
+
static getTopLevel(path: string, entryDir: string): string | null;
|
|
50
|
+
}
|
|
45
51
|
|
|
46
52
|
declare class Context {
|
|
47
53
|
canceled: boolean;
|
|
@@ -295,11 +301,43 @@ declare function defineCommand<const ParamsList extends readonly AnyParam<any>[]
|
|
|
295
301
|
params?: ParamsList;
|
|
296
302
|
}) | string): Command<ParamsList>;
|
|
297
303
|
|
|
304
|
+
declare class BaseClientManager {
|
|
305
|
+
client: BakitClient;
|
|
306
|
+
constructor(client: BakitClient);
|
|
307
|
+
}
|
|
308
|
+
|
|
298
309
|
declare class CommandManager extends BaseClientManager {
|
|
299
310
|
commands: Collection<string, Command<any[]>>;
|
|
300
|
-
|
|
311
|
+
entries: Collection<string, Command<any[]>>;
|
|
312
|
+
loadModules(entryDir: string): Promise<Command[]>;
|
|
313
|
+
/**
|
|
314
|
+
* Load the file and add the command to the registry.
|
|
315
|
+
* @param path The path to the command file.
|
|
316
|
+
* @returns The command object if added successfully.
|
|
317
|
+
*/
|
|
318
|
+
load(path: string): Promise<Command | undefined>;
|
|
319
|
+
/**
|
|
320
|
+
* Unload the file and remove the command from the registry.
|
|
321
|
+
* @param path The path to the command file.
|
|
322
|
+
* @returns The command object if unloaded successfully.
|
|
323
|
+
*/
|
|
324
|
+
unload(path: string): Promise<Command | undefined>;
|
|
325
|
+
/**
|
|
326
|
+
* Add a command to the registry.
|
|
327
|
+
* @param command Command to add.
|
|
328
|
+
*/
|
|
301
329
|
add(command: Command): void;
|
|
330
|
+
/**
|
|
331
|
+
* Remove a command from the registry.
|
|
332
|
+
* @param target Command name or object to remove.
|
|
333
|
+
* @returns The command object if removed successfully.
|
|
334
|
+
*/
|
|
302
335
|
remove(target: string | Command): Command | undefined;
|
|
336
|
+
/**
|
|
337
|
+
* Get a command using its name.
|
|
338
|
+
* @param name The command to get.
|
|
339
|
+
* @returns The command object.
|
|
340
|
+
*/
|
|
303
341
|
get(name: string): Command<any[]> | undefined;
|
|
304
342
|
}
|
|
305
343
|
|
|
@@ -321,11 +359,41 @@ declare function defineListener<const K extends EventKey = EventKey>(options: K
|
|
|
321
359
|
|
|
322
360
|
declare class ListenerManager extends BaseClientManager {
|
|
323
361
|
listeners: Listener[];
|
|
362
|
+
entries: Collection<string, Listener<keyof BakitClientEvents>>;
|
|
324
363
|
private executors;
|
|
325
|
-
loadModules(): Promise<Listener[]>;
|
|
364
|
+
loadModules(entryDir: string): Promise<Listener[]>;
|
|
365
|
+
/**
|
|
366
|
+
* Load the file and add the listener to the registry.
|
|
367
|
+
* @param path The path to the listener file.
|
|
368
|
+
* @returns The listener object if added successfully.
|
|
369
|
+
*/
|
|
370
|
+
load(path: string): Promise<Listener | undefined>;
|
|
371
|
+
/**
|
|
372
|
+
* Unload the file and remove the listener from the registry.
|
|
373
|
+
* @param path The path to the listener file.
|
|
374
|
+
* @returns The listener object if unloaded successfully.
|
|
375
|
+
*/
|
|
376
|
+
unload(path: string): Promise<Listener | undefined>;
|
|
377
|
+
/**
|
|
378
|
+
* Add a listener to the registry and create a listener for client.
|
|
379
|
+
* @param listener Listener to add.
|
|
380
|
+
*/
|
|
326
381
|
add(listener: Listener): void;
|
|
382
|
+
/**
|
|
383
|
+
* Remove a listener from the registry and client.
|
|
384
|
+
* @param target Listener name or object to remove.
|
|
385
|
+
* @returns The list of listener objects if removed successfully.
|
|
386
|
+
*/
|
|
327
387
|
remove(target: string | Listener): Listener[];
|
|
388
|
+
/**
|
|
389
|
+
* Get a list of required intents for Bakit to run correctly.
|
|
390
|
+
* @returns Used intents.
|
|
391
|
+
*/
|
|
328
392
|
getBaseIntents(): IntentsBitField;
|
|
393
|
+
/**
|
|
394
|
+
* Get a list of needed intents based on registered listeners to receive needed events.
|
|
395
|
+
* @returns Used intents.
|
|
396
|
+
*/
|
|
329
397
|
getNeededIntents(): IntentsBitField;
|
|
330
398
|
}
|
|
331
399
|
|
|
@@ -345,8 +413,10 @@ declare class Instance {
|
|
|
345
413
|
cache: ProjectCacheManager;
|
|
346
414
|
constructor();
|
|
347
415
|
start(): Promise<void>;
|
|
416
|
+
private initProcess;
|
|
348
417
|
private loadModules;
|
|
349
418
|
private initIntents;
|
|
419
|
+
private onProcessMessage;
|
|
350
420
|
}
|
|
351
421
|
declare function useApp(): Instance;
|
|
352
422
|
|
|
@@ -379,11 +449,6 @@ declare class BakitClient<Ready extends boolean = boolean> extends Client<Ready>
|
|
|
379
449
|
[inspect.custom](): string;
|
|
380
450
|
}
|
|
381
451
|
|
|
382
|
-
declare class BaseClientManager {
|
|
383
|
-
client: BakitClient;
|
|
384
|
-
constructor(client: BakitClient);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
452
|
declare const Params: {
|
|
388
453
|
readonly string: <Required extends boolean = true>(options: string | {
|
|
389
454
|
name: string;
|
|
@@ -406,6 +471,24 @@ declare const Params: {
|
|
|
406
471
|
}) => UserParam<Required>;
|
|
407
472
|
};
|
|
408
473
|
|
|
474
|
+
interface DevManagerOptions {
|
|
475
|
+
rootDir: string;
|
|
476
|
+
entry: string;
|
|
477
|
+
hotDirs: string[];
|
|
478
|
+
}
|
|
479
|
+
declare class DevProcessManager {
|
|
480
|
+
private options;
|
|
481
|
+
private child;
|
|
482
|
+
private restartTimer;
|
|
483
|
+
constructor(options: DevManagerOptions);
|
|
484
|
+
start(): void;
|
|
485
|
+
private startChild;
|
|
486
|
+
private restartChild;
|
|
487
|
+
private startWatcher;
|
|
488
|
+
private onFileChanged;
|
|
489
|
+
private scheduleRestart;
|
|
490
|
+
}
|
|
491
|
+
|
|
409
492
|
declare class BakitError extends Error {
|
|
410
493
|
constructor(message: string);
|
|
411
494
|
}
|
|
@@ -416,4 +499,4 @@ declare class ArgumentError extends BakitError {
|
|
|
416
499
|
constructor(target: string, reason: string);
|
|
417
500
|
}
|
|
418
501
|
|
|
419
|
-
export {
|
|
502
|
+
export { type AnyParam, ArgumentError, BakitClient, type BakitClientEvents, BakitError, BaseClientManager, BaseCommandContext, BaseParam, type BaseParamOptions, BaseParamSchema, ChatInputContext, type ChatInputContextSendOptions, Command, type CommandContext, CommandManager, type CommandOptions, type CommandOptionsInput, CommandOptionsSchema, Context, type ContextSendOptions, DevProcessManager, EVENT_INTENT_MAPPING, type ErrorHookCallback, type GetPrefixFunction, HookOrder, HookState, type InferParamTuple, type InferParamValue, Instance, LifecycleManager, Listener, ListenerManager, type ListenerOptions, ListenerOptionsSchema, type MainHookCallback, MessageContext, type MessageContextSendOptions, Module, type NumberOptions, NumberParam, NumberParamSchema, type ParamResolvedOutputType, ParamUserType, Params, ProjectCacheManager, type ProjectConfig, type ProjectConfigInput, ProjectConfigSchema, type StringOptions, StringParam, StringParamSchema, type UserOptions, UserParam, UserParamSchema, defineCommand, defineConfig, defineListener, extractSnowflakeId, getConfig, loadConfig, tokenize, useApp, validateParamsOrder };
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { GatewayIntentBits, Events, Client,
|
|
1
|
+
import { GatewayIntentBits, Events, Client, Collection, IntentsBitField, SlashCommandBuilder, SlashCommandStringOption, SlashCommandNumberOption, SlashCommandUserOption, ChatInputCommandInteraction, Message } from 'discord.js';
|
|
2
2
|
import z4, { z } from 'zod';
|
|
3
3
|
import glob from 'tiny-glob';
|
|
4
4
|
import { createJiti } from 'jiti';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import path, { relative, sep, posix, join, dirname } from 'path';
|
|
5
7
|
import { inspect } from 'util';
|
|
6
|
-
import {
|
|
8
|
+
import { fork } from 'child_process';
|
|
9
|
+
import chokidar from 'chokidar';
|
|
7
10
|
import { existsSync, mkdirSync, rmSync } from 'fs';
|
|
8
11
|
import { mkdir, writeFile, readFile, rm } from 'fs/promises';
|
|
9
12
|
import { createHash } from 'crypto';
|
|
@@ -132,9 +135,38 @@ function extractSnowflakeId(input) {
|
|
|
132
135
|
let idMatch = /^(\d{17,20})$/.exec(input);
|
|
133
136
|
return idMatch?.[1] ? idMatch[1] : null;
|
|
134
137
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
+
var Module = class {
|
|
139
|
+
static jiti = createJiti(process.cwd());
|
|
140
|
+
static async import(module, defaultImport = false) {
|
|
141
|
+
let path2 = this.resolve(module);
|
|
142
|
+
if (!path2)
|
|
143
|
+
return null;
|
|
144
|
+
try {
|
|
145
|
+
return await this.jiti.import(path2, { default: defaultImport });
|
|
146
|
+
} catch (error) {
|
|
147
|
+
return console.error(`[Module] Import failed for ${path2}:`, error), null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
static isLoaded(module) {
|
|
151
|
+
let path2 = this.resolve(module);
|
|
152
|
+
return !!path2 && !!this.jiti.cache[path2];
|
|
153
|
+
}
|
|
154
|
+
static unload(module) {
|
|
155
|
+
let path2 = this.resolve(module);
|
|
156
|
+
return !path2 || !this.jiti.cache[path2] ? false : (delete this.jiti.cache[path2], true);
|
|
157
|
+
}
|
|
158
|
+
static resolve(module) {
|
|
159
|
+
try {
|
|
160
|
+
let url = this.jiti.esmResolve(module);
|
|
161
|
+
return fileURLToPath(url);
|
|
162
|
+
} catch {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
static getTopLevel(path2, entryDir) {
|
|
167
|
+
return relative(entryDir, path2).split(sep)[0] ?? null;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
138
170
|
|
|
139
171
|
// src/config.ts
|
|
140
172
|
var ProjectConfigSchema = z.object({
|
|
@@ -156,22 +188,13 @@ var ProjectConfigSchema = z.object({
|
|
|
156
188
|
* @see {@link https://discord.js.org/docs/packages/discord.js/main/ClientOptions:Interface}
|
|
157
189
|
*/
|
|
158
190
|
clientOptions: z.custom().optional(),
|
|
159
|
-
/**
|
|
160
|
-
* The path to the main project source directory.
|
|
161
|
-
*
|
|
162
|
-
* @defaultvalue `src`
|
|
163
|
-
*/
|
|
164
|
-
entryDir: z.string().default("src"),
|
|
165
191
|
prefixes: z.array(z.string()).default([]),
|
|
166
192
|
token: z.string()
|
|
167
193
|
});
|
|
168
194
|
function defineConfig(config) {
|
|
169
195
|
return config;
|
|
170
196
|
}
|
|
171
|
-
var _config;
|
|
172
197
|
async function loadConfig(cwd = process.cwd()) {
|
|
173
|
-
if (_config)
|
|
174
|
-
return console.warn("loadConfig() was called more than once. This shouldn't happen."), _config;
|
|
175
198
|
let globPattern = `bakit.config.{${["ts", "js"].join(",")}}`, [configPath, other] = await glob(globPattern, {
|
|
176
199
|
cwd: cwd.replace(/\\/g, "/"),
|
|
177
200
|
// ensure the path uses `/` instead of `\` on Windows
|
|
@@ -180,22 +203,13 @@ async function loadConfig(cwd = process.cwd()) {
|
|
|
180
203
|
if (!configPath)
|
|
181
204
|
throw new Error("Missing config file");
|
|
182
205
|
other && console.warn(`Multiple config files found in ${cwd}. Using ${configPath}.`);
|
|
183
|
-
let config = await
|
|
184
|
-
return
|
|
206
|
+
let config = await Module.import(configPath, true);
|
|
207
|
+
return Object.freeze(await ProjectConfigSchema.parseAsync(config));
|
|
185
208
|
}
|
|
186
209
|
function getConfig() {
|
|
187
|
-
|
|
188
|
-
throw new Error("Project config is not loaded.");
|
|
189
|
-
return _config;
|
|
210
|
+
throw new Error("Project config is not loaded.");
|
|
190
211
|
}
|
|
191
212
|
|
|
192
|
-
// src/base/BaseClientManager.ts
|
|
193
|
-
var BaseClientManager = class {
|
|
194
|
-
constructor(client) {
|
|
195
|
-
this.client = client;
|
|
196
|
-
}
|
|
197
|
-
};
|
|
198
|
-
|
|
199
213
|
// src/base/lifecycle/Context.ts
|
|
200
214
|
var Context = class {
|
|
201
215
|
canceled = false;
|
|
@@ -569,31 +583,55 @@ function defineCommand(options) {
|
|
|
569
583
|
return new Command(options);
|
|
570
584
|
}
|
|
571
585
|
|
|
586
|
+
// src/base/client/BaseClientManager.ts
|
|
587
|
+
var BaseClientManager = class {
|
|
588
|
+
constructor(client) {
|
|
589
|
+
this.client = client;
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
|
|
572
593
|
// src/base/command/CommandManager.ts
|
|
573
594
|
var CommandManager = class extends BaseClientManager {
|
|
574
595
|
commands = new Collection();
|
|
575
|
-
|
|
576
|
-
|
|
596
|
+
entries = new Collection();
|
|
597
|
+
async loadModules(entryDir) {
|
|
598
|
+
let pattern = posix.join(posix.resolve(entryDir), "commands", "**/*.{ts,js}"), files = await glob(pattern, {
|
|
577
599
|
cwd: process.cwd(),
|
|
578
600
|
absolute: true
|
|
579
|
-
})
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
601
|
+
}), filtered = (await Promise.all(files.map((file) => this.load(file)))).filter((c) => !!c);
|
|
602
|
+
return console.log(`[Loader] Loaded ${filtered.length}/${files.length}`), filtered;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Load the file and add the command to the registry.
|
|
606
|
+
* @param path The path to the command file.
|
|
607
|
+
* @returns The command object if added successfully.
|
|
608
|
+
*/
|
|
609
|
+
async load(path2) {
|
|
610
|
+
let command = await Module.import(path2, true);
|
|
611
|
+
if (!command) {
|
|
612
|
+
console.warn(`[Loader] File has no default export: ${path2}`);
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
if (!(command instanceof Command)) {
|
|
616
|
+
console.warn(`[Loader] Default export is not a Command: ${path2}`);
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
return this.add(command), this.entries.set(path2, command), command;
|
|
596
620
|
}
|
|
621
|
+
/**
|
|
622
|
+
* Unload the file and remove the command from the registry.
|
|
623
|
+
* @param path The path to the command file.
|
|
624
|
+
* @returns The command object if unloaded successfully.
|
|
625
|
+
*/
|
|
626
|
+
async unload(path2) {
|
|
627
|
+
let command = this.entries.get(path2);
|
|
628
|
+
if (Module.isLoaded(path2) && (command ??= await Module.import(path2, true), Module.unload(path2)), this.entries.delete(path2), !!command)
|
|
629
|
+
return this.remove(command);
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Add a command to the registry.
|
|
633
|
+
* @param command Command to add.
|
|
634
|
+
*/
|
|
597
635
|
add(command) {
|
|
598
636
|
if (!(command instanceof Command))
|
|
599
637
|
throw new Error("Invalid command provided");
|
|
@@ -604,11 +642,23 @@ var CommandManager = class extends BaseClientManager {
|
|
|
604
642
|
}
|
|
605
643
|
this.commands.set(name, command);
|
|
606
644
|
}
|
|
645
|
+
/**
|
|
646
|
+
* Remove a command from the registry.
|
|
647
|
+
* @param target Command name or object to remove.
|
|
648
|
+
* @returns The command object if removed successfully.
|
|
649
|
+
*/
|
|
607
650
|
remove(target) {
|
|
651
|
+
if (typeof target != "string" && !(target instanceof Command))
|
|
652
|
+
return;
|
|
608
653
|
let name = typeof target == "string" ? target : target.options.name, existing = this.commands.get(name);
|
|
609
654
|
if (existing)
|
|
610
655
|
return this.commands.delete(name), existing;
|
|
611
656
|
}
|
|
657
|
+
/**
|
|
658
|
+
* Get a command using its name.
|
|
659
|
+
* @param name The command to get.
|
|
660
|
+
* @returns The command object.
|
|
661
|
+
*/
|
|
612
662
|
get(name) {
|
|
613
663
|
return this.commands.get(name);
|
|
614
664
|
}
|
|
@@ -628,40 +678,59 @@ function defineListener(options) {
|
|
|
628
678
|
}
|
|
629
679
|
var ListenerManager = class extends BaseClientManager {
|
|
630
680
|
listeners = [];
|
|
631
|
-
|
|
681
|
+
entries = new Collection();
|
|
632
682
|
executors = /* @__PURE__ */ new WeakMap();
|
|
633
|
-
async loadModules() {
|
|
634
|
-
let
|
|
683
|
+
async loadModules(entryDir) {
|
|
684
|
+
let pattern = posix.join(posix.resolve(entryDir), "listeners", "**/*.{ts,js}"), files = await glob(pattern, {
|
|
635
685
|
cwd: process.cwd(),
|
|
636
686
|
absolute: true
|
|
637
|
-
})
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
687
|
+
}), filtered = (await Promise.all(files.map((file) => this.load(file)))).filter((l) => !!l);
|
|
688
|
+
return console.log(`[Loader] Loaded ${filtered.length}/${files.length}`), filtered;
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Load the file and add the listener to the registry.
|
|
692
|
+
* @param path The path to the listener file.
|
|
693
|
+
* @returns The listener object if added successfully.
|
|
694
|
+
*/
|
|
695
|
+
async load(path2) {
|
|
696
|
+
let listener = await Module.import(path2, true);
|
|
697
|
+
if (!listener) {
|
|
698
|
+
console.warn(`[Loader] File has no default export: ${path2}`);
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
if (!(listener instanceof Listener)) {
|
|
702
|
+
console.warn(`[Loader] Default export is not a Listener: ${path2}`);
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
return this.add(listener), this.entries.set(path2, listener), listener;
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* Unload the file and remove the listener from the registry.
|
|
709
|
+
* @param path The path to the listener file.
|
|
710
|
+
* @returns The listener object if unloaded successfully.
|
|
711
|
+
*/
|
|
712
|
+
async unload(path2) {
|
|
713
|
+
let listener = this.entries.get(path2);
|
|
714
|
+
if (Module.isLoaded(path2) && (listener ??= await Module.import(path2, true), Module.unload(path2)), this.entries.delete(path2), !!listener)
|
|
715
|
+
return this.remove(listener)?.[0];
|
|
654
716
|
}
|
|
717
|
+
/**
|
|
718
|
+
* Add a listener to the registry and create a listener for client.
|
|
719
|
+
* @param listener Listener to add.
|
|
720
|
+
*/
|
|
655
721
|
add(listener) {
|
|
656
722
|
if (!(listener instanceof Listener))
|
|
657
723
|
throw new Error("Invalid listener provided");
|
|
658
|
-
let execute = (...args) => {
|
|
724
|
+
let { once, name } = listener.options, execute = (...args) => {
|
|
659
725
|
listener.execute(new Context(), ...args);
|
|
660
726
|
};
|
|
661
|
-
this.listeners.push(listener), this.executors.set(listener, execute);
|
|
662
|
-
let { once, name } = listener.options;
|
|
663
|
-
this.client[once ? "once" : "on"](name, execute);
|
|
727
|
+
this.listeners.push(listener), this.executors.set(listener, execute), this.client[once ? "once" : "on"](name, execute);
|
|
664
728
|
}
|
|
729
|
+
/**
|
|
730
|
+
* Remove a listener from the registry and client.
|
|
731
|
+
* @param target Listener name or object to remove.
|
|
732
|
+
* @returns The list of listener objects if removed successfully.
|
|
733
|
+
*/
|
|
665
734
|
remove(target) {
|
|
666
735
|
let isMatched = (listener) => typeof target == "string" ? listener.options.name === target : listener === target, removed = [];
|
|
667
736
|
return this.listeners = this.listeners.filter((listener) => {
|
|
@@ -672,9 +741,17 @@ var ListenerManager = class extends BaseClientManager {
|
|
|
672
741
|
return execute && (this.client.removeListener(listener.options.name, execute), this.executors.delete(listener)), false;
|
|
673
742
|
}), removed;
|
|
674
743
|
}
|
|
744
|
+
/**
|
|
745
|
+
* Get a list of required intents for Bakit to run correctly.
|
|
746
|
+
* @returns Used intents.
|
|
747
|
+
*/
|
|
675
748
|
getBaseIntents() {
|
|
676
749
|
return new IntentsBitField([GatewayIntentBits.Guilds]);
|
|
677
750
|
}
|
|
751
|
+
/**
|
|
752
|
+
* Get a list of needed intents based on registered listeners to receive needed events.
|
|
753
|
+
* @returns Used intents.
|
|
754
|
+
*/
|
|
678
755
|
getNeededIntents() {
|
|
679
756
|
let result = this.getBaseIntents();
|
|
680
757
|
for (let listener of this.listeners) {
|
|
@@ -685,7 +762,7 @@ var ListenerManager = class extends BaseClientManager {
|
|
|
685
762
|
}
|
|
686
763
|
};
|
|
687
764
|
|
|
688
|
-
// src/base/BakitClient.ts
|
|
765
|
+
// src/base/client/BakitClient.ts
|
|
689
766
|
var BakitClient2 = class extends Client {
|
|
690
767
|
constructor(options, instance) {
|
|
691
768
|
super(options);
|
|
@@ -738,8 +815,63 @@ var Params = {
|
|
|
738
815
|
number: createFactory(NumberParam),
|
|
739
816
|
user: createFactory(UserParam)
|
|
740
817
|
};
|
|
741
|
-
|
|
742
|
-
|
|
818
|
+
var DevProcessManager = class {
|
|
819
|
+
constructor(options) {
|
|
820
|
+
this.options = options;
|
|
821
|
+
}
|
|
822
|
+
child = null;
|
|
823
|
+
restartTimer = null;
|
|
824
|
+
start() {
|
|
825
|
+
console.log("Starting bakit in dev mode..."), this.startChild(), this.startWatcher();
|
|
826
|
+
}
|
|
827
|
+
startChild() {
|
|
828
|
+
if (this.child) return;
|
|
829
|
+
let entry = path.resolve(this.options.entry);
|
|
830
|
+
this.child = fork(entry, {
|
|
831
|
+
execArgv: ["--import", "tsx"],
|
|
832
|
+
stdio: "inherit",
|
|
833
|
+
env: {
|
|
834
|
+
...process.env,
|
|
835
|
+
NODE_ENV: "development"
|
|
836
|
+
}
|
|
837
|
+
}), this.child.on("exit", () => {
|
|
838
|
+
this.child = null;
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
restartChild() {
|
|
842
|
+
if (!this.child)
|
|
843
|
+
return this.startChild();
|
|
844
|
+
let old = this.child;
|
|
845
|
+
old.once("exit", () => {
|
|
846
|
+
this.child = null, this.startChild();
|
|
847
|
+
}), old.kill("SIGTERM");
|
|
848
|
+
}
|
|
849
|
+
startWatcher() {
|
|
850
|
+
let { rootDir } = this.options;
|
|
851
|
+
chokidar.watch(rootDir, {
|
|
852
|
+
ignoreInitial: true,
|
|
853
|
+
awaitWriteFinish: {
|
|
854
|
+
stabilityThreshold: 200,
|
|
855
|
+
pollInterval: 50
|
|
856
|
+
}
|
|
857
|
+
}).on("change", (file) => this.onFileChanged(file));
|
|
858
|
+
}
|
|
859
|
+
onFileChanged(file) {
|
|
860
|
+
if (!this.child)
|
|
861
|
+
return;
|
|
862
|
+
let top = Module.getTopLevel(file, this.options.rootDir);
|
|
863
|
+
if (top && this.options.hotDirs.includes(top)) {
|
|
864
|
+
this.child.connected && this.child.send({ type: `hmr:${top}`, file });
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
this.scheduleRestart();
|
|
868
|
+
}
|
|
869
|
+
scheduleRestart() {
|
|
870
|
+
this.restartTimer && clearTimeout(this.restartTimer), this.restartTimer = setTimeout(() => {
|
|
871
|
+
console.log("Detected changes, restarting..."), this.restartChild(), this.restartTimer = null;
|
|
872
|
+
}, 150);
|
|
873
|
+
}
|
|
874
|
+
};
|
|
743
875
|
var messageCommandHandler = defineListener(Events.MessageCreate), chatInputCommandHandler = defineListener(Events.InteractionCreate), registerCommandsHandler = defineListener({
|
|
744
876
|
name: Events.ClientReady,
|
|
745
877
|
once: true
|
|
@@ -809,14 +941,14 @@ var ProjectCacheManager = class {
|
|
|
809
941
|
getHash(data) {
|
|
810
942
|
return createHash("sha256").update(JSON.stringify(data)).digest("hex");
|
|
811
943
|
}
|
|
812
|
-
async write(
|
|
813
|
-
let fullPath = join(this.rootDir,
|
|
944
|
+
async write(path2, data) {
|
|
945
|
+
let fullPath = join(this.rootDir, path2), dir = dirname(fullPath);
|
|
814
946
|
await mkdir(dir, { recursive: true });
|
|
815
947
|
let content = typeof data == "string" ? data : JSON.stringify(data);
|
|
816
948
|
await writeFile(fullPath, content, "utf-8");
|
|
817
949
|
}
|
|
818
|
-
async read(
|
|
819
|
-
let fullPath = join(this.rootDir,
|
|
950
|
+
async read(path2) {
|
|
951
|
+
let fullPath = join(this.rootDir, path2);
|
|
820
952
|
try {
|
|
821
953
|
let content = await readFile(fullPath, "utf-8");
|
|
822
954
|
return JSON.parse(content);
|
|
@@ -832,7 +964,7 @@ var ProjectCacheManager = class {
|
|
|
832
964
|
}
|
|
833
965
|
};
|
|
834
966
|
|
|
835
|
-
// src/base/Instance.ts
|
|
967
|
+
// src/base/process/Instance.ts
|
|
836
968
|
var Instance = class {
|
|
837
969
|
client;
|
|
838
970
|
cache;
|
|
@@ -848,19 +980,37 @@ var Instance = class {
|
|
|
848
980
|
...config.clientOptions
|
|
849
981
|
},
|
|
850
982
|
this
|
|
851
|
-
), await this.loadModules(), this.initIntents(), await this.client.login(config.token);
|
|
983
|
+
), await this.loadModules(), this.initIntents(), await this.client.login(config.token), this.initProcess();
|
|
984
|
+
}
|
|
985
|
+
initProcess() {
|
|
986
|
+
process.on("message", (msg) => this.onProcessMessage(msg));
|
|
852
987
|
}
|
|
853
988
|
loadModules() {
|
|
854
989
|
let { managers } = this.client, { commands, listeners } = managers;
|
|
855
|
-
return listeners.add(chatInputCommandHandler), listeners.add(messageCommandHandler), listeners.add(registerCommandsHandler), Promise.all([commands.loadModules(), listeners.loadModules()]);
|
|
990
|
+
return listeners.add(chatInputCommandHandler), listeners.add(messageCommandHandler), listeners.add(registerCommandsHandler), Promise.all([commands.loadModules("src"), listeners.loadModules("src")]);
|
|
856
991
|
}
|
|
857
992
|
initIntents() {
|
|
858
993
|
let config = getConfig(), { options, managers } = this.client, { listeners } = managers, intents;
|
|
859
994
|
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;
|
|
860
995
|
}
|
|
996
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
997
|
+
async onProcessMessage(message) {
|
|
998
|
+
let { type, file } = message;
|
|
999
|
+
if (!type.startsWith("hmr:"))
|
|
1000
|
+
return;
|
|
1001
|
+
let target = type.split(":")[1], { listeners, commands } = this.client.managers;
|
|
1002
|
+
switch (target) {
|
|
1003
|
+
case "listeners":
|
|
1004
|
+
listeners.unload(file), await listeners.load(file);
|
|
1005
|
+
break;
|
|
1006
|
+
case "commands":
|
|
1007
|
+
commands.unload(file), await listeners.load(file);
|
|
1008
|
+
break;
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
861
1011
|
};
|
|
862
1012
|
function useApp() {
|
|
863
1013
|
return new Instance();
|
|
864
1014
|
}
|
|
865
1015
|
|
|
866
|
-
export {
|
|
1016
|
+
export { ArgumentError, BakitClient2 as BakitClient, BakitError, BaseClientManager, BaseCommandContext, BaseParam, BaseParamSchema, ChatInputContext, Command, CommandManager, CommandOptionsSchema, Context, DevProcessManager, EVENT_INTENT_MAPPING, HookOrder, HookState, Instance, LifecycleManager, Listener, ListenerManager, ListenerOptionsSchema, MessageContext, Module, NumberParam, NumberParamSchema, ParamUserType, Params, ProjectCacheManager, ProjectConfigSchema, StringParam, StringParamSchema, UserParam, UserParamSchema, defineCommand, defineConfig, defineListener, extractSnowflakeId, getConfig, loadConfig, tokenize, useApp, validateParamsOrder };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bakit",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.13",
|
|
4
4
|
"description": "A framework for discord.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"test": "vitest run --pass-with-no-tests"
|
|
12
12
|
},
|
|
13
13
|
"bin": {
|
|
14
|
-
"bakit": "./bin/bakit.js"
|
|
14
|
+
"bakit": "./dist/bin/bakit.js"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"dist"
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"discord.js": "^14.0.0"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
+
"chokidar": "^5.0.0",
|
|
40
41
|
"commander": "^14.0.2",
|
|
41
42
|
"dotenv": "^17.2.1",
|
|
42
43
|
"jiti": "^2.6.1",
|
package/bin/bakit.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
import { config as useEnv } from "dotenv";
|
|
3
|
-
import { program } from "commander";
|
|
4
|
-
|
|
5
|
-
program.name("bakit");
|
|
6
|
-
|
|
7
|
-
program.command("dev").action(async () => {
|
|
8
|
-
useEnv({
|
|
9
|
-
path: [".env.local", ".env"],
|
|
10
|
-
quiet: true,
|
|
11
|
-
});
|
|
12
|
-
const { default: nodemon } = await import("nodemon");
|
|
13
|
-
|
|
14
|
-
nodemon({
|
|
15
|
-
script: "src/index.ts",
|
|
16
|
-
exec: `${process.execPath} --import tsx`,
|
|
17
|
-
ext: "ts,js",
|
|
18
|
-
watch: ["src"],
|
|
19
|
-
env: {
|
|
20
|
-
...process.env,
|
|
21
|
-
FORCE_COLOR: "1",
|
|
22
|
-
NODE_ENV: "development",
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
nodemon.on("start", () => {
|
|
27
|
-
console.log("Starting bakit app...");
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
nodemon.on("restart", () => {
|
|
31
|
-
console.log("Bakit detected changes! Restarting...");
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
nodemon.on("quit", () => {
|
|
35
|
-
process.exit();
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
program.parse();
|