@seedcord/gateway 0.1.0-next.1 → 0.1.0-next.2

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/index.cjs CHANGED
@@ -27,27 +27,34 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
 
28
28
  //#endregion
29
29
  require("reflect-metadata");
30
+ let _seedcord_logger_node = require("@seedcord/logger/node");
30
31
  let _seedcord_core = require("@seedcord/core");
31
32
  let _seedcord_core_internal = require("@seedcord/core/internal");
32
33
  let discord_js = require("discord.js");
33
34
  let _seedcord_errors = require("@seedcord/errors");
34
35
  let _seedcord_errors_internal = require("@seedcord/errors/internal");
35
36
  let _seedcord_utils = require("@seedcord/utils");
36
- let _seedcord_services = require("@seedcord/services");
37
- let chalk = require("chalk");
38
- chalk = __toESM(chalk, 1);
37
+ let _seedcord_logger = require("@seedcord/logger");
39
38
  let _discordjs_builders = require("@discordjs/builders");
40
39
  let _seedcord_utils_internal = require("@seedcord/utils/internal");
41
40
  let _seedcord_event_emitter = require("@seedcord/event-emitter");
42
- let node_fs = require("node:fs");
43
- let node_path = require("node:path");
44
- let node_url = require("node:url");
45
41
  let _seedcord_rate_limiter = require("@seedcord/rate-limiter");
42
+ let _seedcord_services = require("@seedcord/services");
46
43
  let _seedcord_types_internal = require("@seedcord/types/internal");
47
44
  let envapt = require("envapt");
45
+ let chalk = require("chalk");
46
+ chalk = __toESM(chalk, 1);
47
+ let envapt_legacy = require("envapt/legacy");
48
+ let node_path = require("node:path");
49
+ let _seedcord_core_hmr = require("@seedcord/core/hmr");
50
+ let _seedcord_utils_node = require("@seedcord/utils/node");
48
51
  let node_crypto = require("node:crypto");
49
52
  node_crypto = __toESM(node_crypto, 1);
50
53
 
54
+ //#region src/logger-bootstrap.ts
55
+ (0, _seedcord_logger_node.installNodeDefaults)();
56
+
57
+ //#endregion
51
58
  //#region src/bot/decorators/Events.ts
52
59
  /**
53
60
  * Registers an event handler class with one or more Discord.js events.
@@ -684,14 +691,14 @@ const Emojis = emojiStorage;
684
691
  */
685
692
  var EmojiInjector = class {
686
693
  core;
687
- logger = new _seedcord_services.Logger("Emojis");
694
+ logger = new _seedcord_logger.Logger("Emojis");
688
695
  constructor(core) {
689
696
  this.core = core;
690
697
  }
691
698
  async init() {
692
699
  this.clearEmojis();
693
700
  if (!this.core.config.bot.emojis || Object.keys(this.core.config.bot.emojis).length === 0) {
694
- this.logger.debug(chalk.default.bold.yellow("No emojis configured, skipping emoji injection."));
701
+ this.logger.debug("No emojis configured, skipping emoji injection.");
695
702
  return;
696
703
  }
697
704
  const configEmojis = this.core.config.bot.emojis;
@@ -759,7 +766,7 @@ const MULTI_GUILD = Symbol("seedcord:commandmentions:multi-guild");
759
766
  */
760
767
  var CommandMentionInjector = class {
761
768
  core;
762
- logger = new _seedcord_services.Logger("CommandMentions");
769
+ logger = new _seedcord_logger.Logger("CommandMentions");
763
770
  constructor(core) {
764
771
  this.core = core;
765
772
  }
@@ -886,7 +893,7 @@ function checkBotPermissions(target, scope, inverse = false, errors) {
886
893
  }
887
894
  const me = target.guild.members.me;
888
895
  if (!me) {
889
- new _seedcord_services.Logger("checkBotPermissions").warn(`Bot member is unavailable in guild ${target.guild.id} while checking permissions in channel ${target.id}`);
896
+ new _seedcord_logger.Logger("checkBotPermissions").warn(`Bot member is unavailable in guild ${target.guild.id} while checking permissions in channel ${target.id}`);
890
897
  const names = scope.map((bit) => PermissionNames.get(bit) ?? String(bit));
891
898
  throw new ((errors?.missing) ?? MissingPermissions)("Missing Permissions", target, names);
892
899
  }
@@ -1112,7 +1119,7 @@ function flagsFor(ephemeral) {
1112
1119
  */
1113
1120
  var ReplySender = class {
1114
1121
  interaction;
1115
- logger = new _seedcord_services.Logger("ReplySender");
1122
+ logger = new _seedcord_logger.Logger("ReplySender");
1116
1123
  constructor(interaction) {
1117
1124
  this.interaction = interaction;
1118
1125
  }
@@ -1248,16 +1255,6 @@ async function getConfirmation(interaction, prompt, options) {
1248
1255
  return confirmed;
1249
1256
  }
1250
1257
 
1251
- //#endregion
1252
- //#region src/hmr/devChannel.ts
1253
- let channel;
1254
- function setDevChannel(next) {
1255
- channel = next;
1256
- }
1257
- function getDevChannel() {
1258
- return channel;
1259
- }
1260
-
1261
1258
  //#endregion
1262
1259
  //#region src/interfaces/Plugin.ts
1263
1260
  /**
@@ -1285,7 +1282,7 @@ var Plugin = class extends _seedcord_event_emitter.TypedEventEmitter {
1285
1282
  * @param patterns - Glob patterns relative to the project root
1286
1283
  */
1287
1284
  registerCriticalFiles(patterns) {
1288
- getDevChannel()?.send("seedcord:register-critical-files", { patterns });
1285
+ (0, _seedcord_core_internal.getDevChannel)()?.send("seedcord:register-critical-files", { patterns });
1289
1286
  }
1290
1287
  /** @internal */
1291
1288
  removeListener(event, listener) {
@@ -1377,7 +1374,7 @@ var BaseHandler = class {
1377
1374
  constructor(event, core, dispatch) {
1378
1375
  this.core = core;
1379
1376
  this.event = event;
1380
- this.logger = new _seedcord_services.Logger(this.constructor.name);
1377
+ this.logger = new _seedcord_logger.Logger(this.constructor.name);
1381
1378
  this.dispatch = dispatch;
1382
1379
  }
1383
1380
  /** @internal */
@@ -2120,7 +2117,7 @@ var Subscriber = class {
2120
2117
  constructor(data, core) {
2121
2118
  this.data = data;
2122
2119
  this.core = core;
2123
- this.logger = new _seedcord_services.Logger(this.constructor.name);
2120
+ this.logger = new _seedcord_logger.Logger(this.constructor.name);
2124
2121
  }
2125
2122
  };
2126
2123
 
@@ -2178,171 +2175,6 @@ var WebhookLog = class extends Subscriber {
2178
2175
  }
2179
2176
  };
2180
2177
 
2181
- //#endregion
2182
- //#region src/hmr/HmrModuleHandler.ts
2183
- /**
2184
- * Reloads THandler and optional TMiddleware modules on HMR updates.
2185
- *
2186
- * You can either implement a custom `onHmr()` method in your class by extending `HmrAware`, or if it's a plugin, override the existing `onHmr()` with fully custom logic. Or, use this class's `handle()` method inside your `onHmr()` to get standard HMR handling for your modules based on the provided options you give to the constructor.
2187
- *
2188
- * This is only useful during development.
2189
- */
2190
- var HmrModuleHandler = class {
2191
- store;
2192
- options;
2193
- constructor(options) {
2194
- this.options = {
2195
- ...options,
2196
- logger: options.logger.inChannel("hmr")
2197
- };
2198
- this.store = {
2199
- fileToHandlers: /* @__PURE__ */ new Map(),
2200
- fileToMiddlewares: /* @__PURE__ */ new Map(),
2201
- handlerArtifacts: /* @__PURE__ */ new Map()
2202
- };
2203
- }
2204
- /**
2205
- * Handles an HMR update event by reloading affected modules based on the event details and config. It receives an {@link HmrUpdateEvent}, then checks the type of update.
2206
- *
2207
- * - If it's a deletion, it unloads the module.
2208
- * - If it's an update/creation, it checks if the file is tracked, unloads it if so, then reloads the file if it is in the handlers or middlewares directory and is a valid handler/middleware.
2209
- */
2210
- async handle(event) {
2211
- const { file, affectedModules, type } = event;
2212
- const { logger, handlersDir, middlewaresDir } = this.options;
2213
- if (type === "delete" || type === "deleteDir") {
2214
- this.unload(file);
2215
- return;
2216
- }
2217
- if (type === "update" && !(0, node_fs.existsSync)(file)) {
2218
- if (this.isTracked(file)) {
2219
- logger.info(`Received update for non-existent file: ${(0, _seedcord_utils.formatFilePath)(file)}, treating as delete`);
2220
- this.unload(file);
2221
- }
2222
- return;
2223
- }
2224
- const rollbackEnabled = event.rollback ?? true;
2225
- const filesToReload = affectedModules && affectedModules.length > 0 ? affectedModules : [file];
2226
- const absHandlersDir = (0, node_path.resolve)(process.cwd(), handlersDir);
2227
- const absMiddlewaresDir = middlewaresDir ? (0, node_path.resolve)(process.cwd(), middlewaresDir) : null;
2228
- for (const fileToReload of filesToReload) {
2229
- const isHandler = fileToReload.startsWith(absHandlersDir);
2230
- const isMiddleware = absMiddlewaresDir ? fileToReload.startsWith(absMiddlewaresDir) : false;
2231
- if (!isHandler && !isMiddleware) continue;
2232
- await this.reloadWithRollback(fileToReload, rollbackEnabled);
2233
- }
2234
- }
2235
- async reloadWithRollback(file, rollbackEnabled) {
2236
- const { logger } = this.options;
2237
- const snapshot = this.snapshotUnits(file);
2238
- this.unload(file);
2239
- if (await this.reloadFile(file)) return;
2240
- this.unload(file);
2241
- if (!rollbackEnabled) return;
2242
- this.restoreUnits(file, snapshot);
2243
- logger.warn(`${chalk.default.yellow.bold("Rolled back")} ${chalk.default.gray((0, _seedcord_utils.formatFilePath)(file))} to the last-good version`);
2244
- }
2245
- /**
2246
- * Tracks a handler module as being loaded from a specific file.
2247
- * @param file - The file path the handler was loaded from.
2248
- * @param handler - The handler module instance.
2249
- */
2250
- trackHandler(file, handler) {
2251
- let set = this.store.fileToHandlers.get(file);
2252
- if (!set) {
2253
- set = /* @__PURE__ */ new Set();
2254
- this.store.fileToHandlers.set(file, set);
2255
- }
2256
- set.add(handler);
2257
- if (this.options.getArtifacts) {
2258
- const artifacts = this.options.getArtifacts(handler);
2259
- this.store.handlerArtifacts.set(handler, artifacts);
2260
- }
2261
- }
2262
- /**
2263
- * Tracks a middleware module as being loaded from a specific file.
2264
- * @param file - The file path the middleware was loaded from.
2265
- * @param middleware - The middleware module instance.
2266
- */
2267
- trackMiddleware(file, middleware) {
2268
- let set = this.store.fileToMiddlewares.get(file);
2269
- if (!set) {
2270
- set = /* @__PURE__ */ new Set();
2271
- this.store.fileToMiddlewares.set(file, set);
2272
- }
2273
- set.add(middleware);
2274
- }
2275
- isTracked(file) {
2276
- return this.store.fileToHandlers.has(file) || this.store.fileToMiddlewares.has(file);
2277
- }
2278
- unload(file) {
2279
- const { logger } = this.options;
2280
- const handlers = this.store.fileToHandlers.get(file);
2281
- if (handlers) {
2282
- for (const handler of handlers) {
2283
- const artifacts = this.store.handlerArtifacts.get(handler);
2284
- this.options.unregisterHandler(handler, artifacts);
2285
- this.store.handlerArtifacts.delete(handler);
2286
- const name = handler.name ?? "Handler";
2287
- logger.info(`${chalk.default.red.bold("Unloaded")} ${chalk.default.cyan.bold(name)} from ${chalk.default.gray((0, _seedcord_utils.formatFilePath)(file))}`);
2288
- }
2289
- this.store.fileToHandlers.delete(file);
2290
- }
2291
- const middlewares = this.store.fileToMiddlewares.get(file);
2292
- if (middlewares) {
2293
- for (const middleware of middlewares) {
2294
- this.options.unregisterMiddleware?.(middleware);
2295
- const name = middleware.name ?? "Middleware";
2296
- logger.info(`${chalk.default.red.bold("Unloaded")} ${chalk.default.cyan.bold(name)} from ${chalk.default.gray((0, _seedcord_utils.formatFilePath)(file))}`);
2297
- }
2298
- this.store.fileToMiddlewares.delete(file);
2299
- }
2300
- }
2301
- async reloadFile(file) {
2302
- const { logger, isHandler, isMiddleware, registerHandler, registerMiddleware } = this.options;
2303
- if (!(0, node_fs.existsSync)(file)) {
2304
- logger.info(`File does not exist, skipping reload: ${(0, _seedcord_utils.formatFilePath)(file)}`);
2305
- return false;
2306
- }
2307
- try {
2308
- let fileUrl = (0, node_url.pathToFileURL)(file).href;
2309
- if (process.env.VITEST === "true") fileUrl += `?update=${Date.now()}`;
2310
- const imported = await import(fileUrl);
2311
- for (const val of Object.values(imported)) if (isHandler(val)) {
2312
- registerHandler(val, file);
2313
- this.trackHandler(file, val);
2314
- const name = val.name ?? "Handler";
2315
- logger.info(`${chalk.default.blue.bold("Reloaded")} ${chalk.default.cyan.bold(name)} from ${chalk.default.gray((0, _seedcord_utils.formatFilePath)(file))}`);
2316
- } else if (isMiddleware && registerMiddleware && isMiddleware(val)) {
2317
- registerMiddleware(val, file);
2318
- this.trackMiddleware(file, val);
2319
- const name = val.name ?? "Middleware";
2320
- logger.info(`${chalk.default.blue.bold("Reloaded")} ${chalk.default.cyan.bold(name)} from ${chalk.default.gray((0, _seedcord_utils.formatFilePath)(file))}`);
2321
- }
2322
- return true;
2323
- } catch (error) {
2324
- logger.error(`Failed to reload file: ${file}`, error);
2325
- return false;
2326
- }
2327
- }
2328
- snapshotUnits(file) {
2329
- return {
2330
- handlers: [...this.store.fileToHandlers.get(file) ?? []],
2331
- middlewares: [...this.store.fileToMiddlewares.get(file) ?? []]
2332
- };
2333
- }
2334
- restoreUnits(file, snapshot) {
2335
- for (const handler of snapshot.handlers) {
2336
- this.options.registerHandler(handler, file);
2337
- this.trackHandler(file, handler);
2338
- }
2339
- if (this.options.registerMiddleware) for (const middleware of snapshot.middlewares) {
2340
- this.options.registerMiddleware(middleware, file);
2341
- this.trackMiddleware(file, middleware);
2342
- }
2343
- }
2344
- };
2345
-
2346
2178
  //#endregion
2347
2179
  //#region src/bot/utilities/miscellaneous/contextMenuLeaves.ts
2348
2180
  /**
@@ -2398,11 +2230,13 @@ var CommandRegistry = class {
2398
2230
  core;
2399
2231
  onDeployed;
2400
2232
  name = "Commands";
2401
- logger = new _seedcord_services.Logger("Commands");
2233
+ logger = new _seedcord_logger.Logger("Commands");
2402
2234
  isInitialised = false;
2403
2235
  globalCommands = [];
2404
2236
  guildCommands = new discord_js.Collection();
2405
2237
  ctorToCommand = /* @__PURE__ */ new Map();
2238
+ loading = false;
2239
+ loadedCommands = [];
2406
2240
  hmrHandler;
2407
2241
  pendingEvents = /* @__PURE__ */ new Map();
2408
2242
  constructor(core, onDeployed) {
@@ -2411,7 +2245,7 @@ var CommandRegistry = class {
2411
2245
  const commandsDir = this.core.config.bot.commands.path;
2412
2246
  if (!commandsDir) throw new _seedcord_errors_internal.SeedcordError(_seedcord_errors.SeedcordErrorCode.CoreControllerPathMissing, ["CommandRegistry", "commands"]);
2413
2247
  if (!envapt.Envapter.isDevelopment && !envapt.Envapter.isTest) return;
2414
- this.hmrHandler = new HmrModuleHandler({
2248
+ this.hmrHandler = new _seedcord_core_hmr.HmrModuleHandler({
2415
2249
  handlersDir: commandsDir,
2416
2250
  isHandler: this.isCommandClass.bind(this),
2417
2251
  registerHandler: this.registerCommand.bind(this),
@@ -2429,15 +2263,32 @@ var CommandRegistry = class {
2429
2263
  this.isInitialised = true;
2430
2264
  const commandsDir = this.core.config.bot.commands.path;
2431
2265
  if (!commandsDir) return;
2432
- this.logger.info(chalk.default.bold(commandsDir));
2433
- await this.loadCommands(commandsDir);
2434
- this.logger.utils.summary("Loaded commands", {
2266
+ this.loading = true;
2267
+ this.loadedCommands.length = 0;
2268
+ try {
2269
+ await this.loadCommands(commandsDir);
2270
+ } finally {
2271
+ this.loading = false;
2272
+ }
2273
+ this.reportLoad();
2274
+ (0, _seedcord_core_internal.getDevChannel)()?.on("seedcord:refresh-commands", (data) => {
2275
+ this.refresh(data.shouldRefresh);
2276
+ });
2277
+ }
2278
+ reportLoad() {
2279
+ const { utils } = this.logger;
2280
+ utils.summary("Loaded commands", {
2435
2281
  global: this.globalCommands.length,
2436
2282
  "guild groups": this.guildCommands.size
2437
2283
  });
2438
- getDevChannel()?.on("seedcord:refresh-commands", (data) => {
2439
- this.refresh(data.shouldRefresh);
2440
- });
2284
+ let slash = 0;
2285
+ let menu = 0;
2286
+ for (const command of this.loadedCommands) if (command.kind === "slash command") slash++;
2287
+ else menu++;
2288
+ utils.block("Loaded commands", [...utils.entries(this.loadedCommands), ...utils.counts({
2289
+ "slash commands": slash,
2290
+ "context menus": menu
2291
+ })]);
2441
2292
  }
2442
2293
  /** @internal */
2443
2294
  async refresh(shouldRefresh = true) {
@@ -2457,11 +2308,11 @@ var CommandRegistry = class {
2457
2308
  if (commandsDir && event.file.startsWith((0, node_path.resolve)(process.cwd(), commandsDir))) {
2458
2309
  this.pendingEvents.delete(event.file);
2459
2310
  this.pendingEvents.set(event.file, event);
2460
- getDevChannel()?.send("seedcord:commands-update-prompt", { files: [...this.pendingEvents.keys()].map((f) => (0, _seedcord_utils.formatFilePath)(f)) });
2311
+ (0, _seedcord_core_internal.getDevChannel)()?.send("seedcord:commands-update-prompt", { files: [...this.pendingEvents.keys()].map((f) => (0, _seedcord_utils.formatFilePath)(f)) });
2461
2312
  } else await this.hmrHandler?.handle(event);
2462
2313
  }
2463
2314
  async loadCommands(dir) {
2464
- await (0, _seedcord_utils.traverseDirectory)(dir, (fullPath, rel, mod) => {
2315
+ await (0, _seedcord_utils_node.traverseDirectory)(dir, (fullPath, rel, mod) => {
2465
2316
  for (const exported of Object.values(mod)) if (this.isCommandClass(exported)) {
2466
2317
  this.registerCommand(exported, rel);
2467
2318
  this.hmrHandler?.trackHandler(fullPath, exported);
@@ -2476,25 +2327,27 @@ var CommandRegistry = class {
2476
2327
  const meta = Reflect.getMetadata(_seedcord_core_internal.CommandMetadataKey, ctor);
2477
2328
  if (!meta) return;
2478
2329
  const comp = new ctor().component;
2479
- const commandType = comp instanceof _discordjs_builders.SlashCommandBuilder ? "slash command" : "context menu command";
2480
- if (meta.scope === "global") {
2481
- this.globalCommands.push(comp);
2482
- this.logger.utils.registration(ctor.name, rel);
2483
- this.logger.utils.item(`Global ${commandType}: ${chalk.default.bold.cyan(comp.name)}`);
2484
- } else {
2485
- for (const g of meta.guilds) {
2486
- const arr = this.guildCommands.get(g) ?? [];
2487
- arr.push(comp);
2488
- this.guildCommands.set(g, arr);
2489
- }
2490
- this.logger.utils.registration(ctor.name, rel);
2491
- this.logger.utils.item(`Guild ${commandType}: ${chalk.default.bold.cyan(comp.name)} for ${chalk.default.magenta.bold(meta.guilds.length)} guild(s)`);
2330
+ const kind = comp instanceof _discordjs_builders.SlashCommandBuilder ? "slash command" : "context menu";
2331
+ if (meta.scope === "global") this.globalCommands.push(comp);
2332
+ else for (const g of meta.guilds) {
2333
+ const arr = this.guildCommands.get(g) ?? [];
2334
+ arr.push(comp);
2335
+ this.guildCommands.set(g, arr);
2492
2336
  }
2493
2337
  this.ctorToCommand.set(ctor, {
2494
2338
  name: comp.name,
2495
2339
  scope: meta.scope,
2496
2340
  ...meta.scope === "guild" && { guilds: meta.guilds }
2497
2341
  });
2342
+ if (this.loading) {
2343
+ this.loadedCommands.push({
2344
+ name: comp.name,
2345
+ from: (0, _seedcord_utils.formatFilePath)(rel),
2346
+ kind
2347
+ });
2348
+ return;
2349
+ }
2350
+ this.logger.utils.registration(comp.name, rel, `${meta.scope} ${kind}`);
2498
2351
  }
2499
2352
  unregisterCommand(ctor, artifacts) {
2500
2353
  const info = artifacts ?? this.ctorToCommand.get(ctor);
@@ -2521,8 +2374,7 @@ var CommandRegistry = class {
2521
2374
  const deployed = await this.core.bot.client.application?.commands.set(this.globalCommands);
2522
2375
  if (deployed) result.global = deployed;
2523
2376
  const tag = this.globalCommands.length === 1 ? "command" : "commands";
2524
- this.logger.utils.summary("Configured global", { [tag]: this.globalCommands.length });
2525
- this.logger.utils.item(`${this.globalCommands.map((command) => chalk.default.bold.cyan(command.name)).join(", ")}`);
2377
+ this.logger.utils.block(`Deployed ${this.globalCommands.length} global ${tag}`, this.logger.utils.wrap(this.globalCommands.map((command) => command.name)), "info");
2526
2378
  }
2527
2379
  for (const [guildId, commands] of this.guildCommands.entries()) {
2528
2380
  const guild = this.core.bot.client.guilds.cache.get(guildId);
@@ -2533,8 +2385,7 @@ var CommandRegistry = class {
2533
2385
  const deployed = await guild.commands.set(commands);
2534
2386
  result.guilds.set(guildId, deployed);
2535
2387
  const tag = commands.length === 1 ? "command" : "commands";
2536
- this.logger.utils.summary(`Configured commands for ${chalk.default.bold.yellow(guild.name)}`, { [tag]: commands.length });
2537
- this.logger.utils.item(`${commands.map((command) => chalk.default.bold.cyan(command.name)).join(", ")}`);
2388
+ this.logger.utils.block(`Deployed ${commands.length} ${tag} to ${_seedcord_logger.paint.amber.bold(guild.name)}`, this.logger.utils.wrap(commands.map((command) => command.name)), "info");
2538
2389
  }
2539
2390
  this.onDeployed?.(result);
2540
2391
  return result;
@@ -2655,7 +2506,7 @@ var FaultThrottle = class {
2655
2506
 
2656
2507
  //#endregion
2657
2508
  //#region src/miscellaneous/extractErrorResponse.ts
2658
- const logger$2 = new _seedcord_services.Logger("ErrorsHandling");
2509
+ const logger$2 = new _seedcord_logger.Logger("ErrorsHandling");
2659
2510
  /**
2660
2511
  * The single throttle for every fault publish, so a recurring fault reports once per window across both
2661
2512
  * the interaction and event paths. Exported so tests reset it between cases.
@@ -2795,7 +2646,7 @@ function interactionKind(interaction) {
2795
2646
 
2796
2647
  //#endregion
2797
2648
  //#region src/bot/handleEventFault.ts
2798
- const logger$1 = new _seedcord_services.Logger("EventBoundary");
2649
+ const logger$1 = new _seedcord_logger.Logger("EventBoundary");
2799
2650
  /**
2800
2651
  * The event controller boundary. Reports a throw from an event handler and never replies, since a
2801
2652
  * generic event has no reply target. A {@link Silence} or a non-reporting {@link Notice} stops quietly, a
@@ -2839,20 +2690,23 @@ function handleEventFault(caught, eventName, handlerName, args, core) {
2839
2690
  */
2840
2691
  var EventDispatcher = class {
2841
2692
  core;
2842
- logger = new _seedcord_services.Logger("Events");
2693
+ logger = new _seedcord_logger.Logger("Events");
2843
2694
  isInitialized = false;
2844
2695
  name = "Events";
2845
2696
  eventMap = /* @__PURE__ */ new Map();
2846
2697
  middlewares = [];
2847
2698
  executedOnceHandlers = /* @__PURE__ */ new Set();
2848
2699
  attachedEvents = /* @__PURE__ */ new Set();
2700
+ loading = false;
2701
+ loadedHandlers = [];
2702
+ loadedMiddlewares = [];
2849
2703
  hmrHandler;
2850
2704
  constructor(core) {
2851
2705
  this.core = core;
2852
2706
  const eventsDir = this.core.config.bot.events.path;
2853
2707
  if (!eventsDir) throw new _seedcord_errors_internal.SeedcordError(_seedcord_errors.SeedcordErrorCode.CoreControllerPathMissing, ["EventDispatcher", "events"]);
2854
2708
  if (!envapt.Envapter.isDevelopment && !envapt.Envapter.isTest) return;
2855
- this.hmrHandler = new HmrModuleHandler({
2709
+ this.hmrHandler = new _seedcord_core_hmr.HmrModuleHandler({
2856
2710
  handlersDir: eventsDir,
2857
2711
  ...(0, _seedcord_utils.hasKeys)(this.core.config.bot.events, ["middlewares"]) && { middlewaresDir: this.core.config.bot.events.middlewares },
2858
2712
  isHandler: this.isEventHandlerClass.bind(this),
@@ -2875,23 +2729,32 @@ var EventDispatcher = class {
2875
2729
  this.isInitialized = true;
2876
2730
  const handlersDir = this.core.config.bot.events.path;
2877
2731
  if (!handlersDir) return;
2878
- this.logger.info(chalk.default.bold(handlersDir));
2879
2732
  const middlewareDir = (0, _seedcord_utils.hasKeys)(this.core.config.bot.events, ["middlewares"]) ? this.core.config.bot.events.middlewares : void 0;
2880
- if (middlewareDir) {
2881
- this.logger.info(`${chalk.default.bold(middlewareDir)} ${chalk.default.gray("(middlewares)")}`);
2882
- await this.loadMiddlewares(middlewareDir);
2733
+ this.loading = true;
2734
+ this.loadedHandlers.length = 0;
2735
+ this.loadedMiddlewares.length = 0;
2736
+ try {
2737
+ if (middlewareDir) await this.loadMiddlewares(middlewareDir);
2738
+ await this.loadHandlers(handlersDir);
2739
+ } finally {
2740
+ this.loading = false;
2883
2741
  }
2884
- await this.loadHandlers(handlersDir);
2885
2742
  this.attachToClient();
2886
- this.logger.info(`${chalk.default.bold.green("Loaded event handlers:")}`);
2887
- const eventList = [`${chalk.default.magenta.bold(this.middlewares.length)} middlewares`];
2888
- this.eventMap.forEach((handlers, eventName) => {
2889
- eventList.push(`${chalk.default.magenta.bold(handlers.length)} ${eventName}`);
2743
+ this.reportLoad();
2744
+ }
2745
+ reportLoad() {
2746
+ const { utils } = this.logger;
2747
+ utils.summary("Loaded", {
2748
+ "event handlers": this.loadedHandlers.length,
2749
+ middlewares: this.loadedMiddlewares.length
2890
2750
  });
2891
- this.logger.utils.list(eventList);
2751
+ if (this.loadedMiddlewares.length > 0) utils.block("Loaded event middlewares", utils.entries(this.loadedMiddlewares));
2752
+ const perEvent = {};
2753
+ for (const [event, handlers] of this.eventMap) perEvent[event] = handlers.length;
2754
+ utils.block("Loaded event handlers", [...utils.entries(this.loadedHandlers), ...utils.counts(perEvent)]);
2892
2755
  }
2893
2756
  async loadHandlers(dir) {
2894
- await (0, _seedcord_utils.traverseDirectory)(dir, (fullPath, relativePath, imported) => {
2757
+ await (0, _seedcord_utils_node.traverseDirectory)(dir, (fullPath, relativePath, imported) => {
2895
2758
  for (const val of Object.values(imported)) {
2896
2759
  if (!this.isEventHandlerClass(val)) continue;
2897
2760
  this.registerHandler(val, relativePath);
@@ -2900,7 +2763,7 @@ var EventDispatcher = class {
2900
2763
  }, this.logger);
2901
2764
  }
2902
2765
  async loadMiddlewares(dir) {
2903
- await (0, _seedcord_utils.traverseDirectory)(dir, (fullPath, relativePath, imported) => {
2766
+ await (0, _seedcord_utils_node.traverseDirectory)(dir, (fullPath, relativePath, imported) => {
2904
2767
  for (const val of Object.values(imported)) {
2905
2768
  if (!this.isMiddlewareClass(val)) continue;
2906
2769
  this.registerMiddleware(val, relativePath);
@@ -2938,7 +2801,14 @@ var EventDispatcher = class {
2938
2801
  ...metadata.events && { events: metadata.events }
2939
2802
  });
2940
2803
  this.middlewares.sort((a, b) => a.priority - b.priority);
2941
- this.logger.utils.registration(`${middlewareCtor.name} ${chalk.default.gray(`(${metadata.priority})`)}`, relativePath, "event middleware");
2804
+ if (this.loading) {
2805
+ this.loadedMiddlewares.push({
2806
+ name: `${middlewareCtor.name} (${metadata.priority})`,
2807
+ from: (0, _seedcord_utils.formatFilePath)(relativePath)
2808
+ });
2809
+ return;
2810
+ }
2811
+ this.logger.utils.registration(`${middlewareCtor.name} ${_seedcord_logger.paint.mute(`(${metadata.priority})`)}`, relativePath, "event middleware");
2942
2812
  }
2943
2813
  async runMiddlewares(eventName, args) {
2944
2814
  for (const { ctor, events } of this.middlewares) {
@@ -2979,7 +2849,12 @@ var EventDispatcher = class {
2979
2849
  const names = areRoutes(raw) ? raw : typeof raw === "string" ? [raw] : [];
2980
2850
  for (const name of names) register(name, "on");
2981
2851
  }
2982
- this.logger.utils.registration(handlerClass.name, relativePath);
2852
+ const from = (0, _seedcord_utils.formatFilePath)(relativePath);
2853
+ if (this.loading) this.loadedHandlers.push({
2854
+ name: handlerClass.name,
2855
+ from
2856
+ });
2857
+ else this.logger.utils.registration(handlerClass.name, from);
2983
2858
  }
2984
2859
  attachToClient() {
2985
2860
  for (const [eventName] of this.eventMap) this.attachListener(eventName);
@@ -2988,12 +2863,12 @@ var EventDispatcher = class {
2988
2863
  if (this.attachedEvents.has(eventName)) return;
2989
2864
  this.attachedEvents.add(eventName);
2990
2865
  const handlerEntries = this.eventMap.get(eventName);
2991
- this.logger.debug(`Attaching ${chalk.default.bold.green(eventName)} to the client with ${chalk.default.gray(handlerEntries?.length ?? 0)} handler(s)`);
2866
+ this.logger.debug(`Attaching ${_seedcord_logger.paint.mint.bold(eventName)} to the client with ${_seedcord_logger.paint.mute(handlerEntries?.length ?? 0)} handler(s)`);
2992
2867
  this.core.bot.client.on(eventName, (...args) => {
2993
2868
  this.core.bot.emitSafe("any:event", eventName, ...args);
2994
2869
  (async () => {
2995
2870
  await this.processEvent(eventName, args).catch((err) => {
2996
- this.logger.error(`[${chalk.default.bold.red("UNHANDLED ERROR AT ROOT")}] ${err.name}`, err.stack);
2871
+ this.logger.error(`[${_seedcord_logger.paint.coral.bold("UNHANDLED ERROR AT ROOT")}] ${err.name}`, err.stack);
2997
2872
  this.core.bot.emit("error:unhandled:event", err);
2998
2873
  });
2999
2874
  })();
@@ -3015,7 +2890,7 @@ var EventDispatcher = class {
3015
2890
  }
3016
2891
  async processHandler(eventName, ctor, args) {
3017
2892
  try {
3018
- this.logger.debug(`Processing ${chalk.default.bold.green(eventName)} with ${chalk.default.gray(ctor.name)}`);
2893
+ this.logger.debug(`Processing ${_seedcord_logger.paint.mint.bold(eventName)} with ${_seedcord_logger.paint.mute(ctor.name)}`);
3019
2894
  const handler = new ctor(args, this.core, eventName);
3020
2895
  await (0, _seedcord_core_internal.runHandlerGates)(ctor, eventGateContext(eventName, args, this.core));
3021
2896
  await handler.execute();
@@ -3044,7 +2919,7 @@ var UnhandledEvent = class extends InteractionHandler {
3044
2919
 
3045
2920
  //#endregion
3046
2921
  //#region src/bot/handleInteractionFault.ts
3047
- const logger = new _seedcord_services.Logger("InteractionBoundary");
2922
+ const logger = new _seedcord_logger.Logger("InteractionBoundary");
3048
2923
  /**
3049
2924
  * The interaction controller boundary. Sorts a throw from any handler-lifecycle phase into the right
3050
2925
  * user reply plus the right bus event, building a {@link ReplySender} lazily so it reads the live
@@ -3091,7 +2966,7 @@ async function handleInteractionFault(caught, interaction, core) {
3091
2966
  */
3092
2967
  var InteractionDispatcher = class {
3093
2968
  core;
3094
- logger = new _seedcord_services.Logger("Interactions");
2969
+ logger = new _seedcord_logger.Logger("Interactions");
3095
2970
  isInitialized = false;
3096
2971
  name = "Interactions";
3097
2972
  slashMap = /* @__PURE__ */ new Map();
@@ -3107,6 +2982,9 @@ var InteractionDispatcher = class {
3107
2982
  autocompleteMap = /* @__PURE__ */ new Map();
3108
2983
  keysToIgnore = /* @__PURE__ */ new Set();
3109
2984
  middlewares = [];
2985
+ loading = false;
2986
+ loadedHandlers = [];
2987
+ loadedMiddlewares = [];
3110
2988
  hmrHandler;
3111
2989
  routeTypes = [
3112
2990
  [_seedcord_core_internal.InteractionRoutes.Slash, this.slashMap],
@@ -3129,7 +3007,7 @@ var InteractionDispatcher = class {
3129
3007
  const interactionsDir = this.core.config.bot.interactions.path;
3130
3008
  if (!interactionsDir) throw new _seedcord_errors_internal.SeedcordError(_seedcord_errors.SeedcordErrorCode.CoreControllerPathMissing, ["InteractionDispatcher", "interactions"]);
3131
3009
  if (!envapt.Envapter.isDevelopment && !envapt.Envapter.isTest) return;
3132
- this.hmrHandler = new HmrModuleHandler({
3010
+ this.hmrHandler = new _seedcord_core_hmr.HmrModuleHandler({
3133
3011
  handlersDir: interactionsDir,
3134
3012
  ...(0, _seedcord_utils.hasKeys)(this.core.config.bot.interactions, ["middlewares"]) && this.core.config.bot.interactions.middlewares && { middlewaresDir: this.core.config.bot.interactions.middlewares },
3135
3013
  isHandler: this.isHandlerClass.bind(this),
@@ -3149,7 +3027,7 @@ var InteractionDispatcher = class {
3149
3027
  * @internal
3150
3028
  */
3151
3029
  warnUnhandledRoutes(commandLeaves) {
3152
- for (const route of commandLeaves) if (!this.slashMap.has(route)) this.logger.warn(`Slash route ${chalk.default.bold.cyan(route)} has no registered ${chalk.default.bold("@SlashRoute")} handler.`);
3030
+ for (const route of commandLeaves) if (!this.slashMap.has(route)) this.logger.warn(`Slash route ${_seedcord_logger.paint.sky.bold(route)} has no registered ${chalk.default.bold("@SlashRoute")} handler.`);
3153
3031
  }
3154
3032
  /**
3155
3033
  * Warns for each context-menu command with no matching handler, which would fall through to UnhandledEvent
@@ -3158,8 +3036,8 @@ var InteractionDispatcher = class {
3158
3036
  * @internal
3159
3037
  */
3160
3038
  warnUnhandledContextMenuRoutes(leaves) {
3161
- for (const name of leaves.user) if (!this.userContextMenuMap.has(name)) this.logger.warn(`User context menu ${chalk.default.bold.cyan(name)} has no registered ${chalk.default.bold("@ContextMenuRoute")} handler.`);
3162
- for (const name of leaves.message) if (!this.messageContextMenuMap.has(name)) this.logger.warn(`Message context menu ${chalk.default.bold.cyan(name)} has no registered ${chalk.default.bold("@ContextMenuRoute")} handler.`);
3039
+ for (const name of leaves.user) if (!this.userContextMenuMap.has(name)) this.logger.warn(`User context menu ${_seedcord_logger.paint.sky.bold(name)} has no registered ${chalk.default.bold("@ContextMenuRoute")} handler.`);
3040
+ for (const name of leaves.message) if (!this.messageContextMenuMap.has(name)) this.logger.warn(`Message context menu ${_seedcord_logger.paint.sky.bold(name)} has no registered ${chalk.default.bold("@ContextMenuRoute")} handler.`);
3163
3041
  }
3164
3042
  getArtifacts(handlerClass) {
3165
3043
  const artifacts = [];
@@ -3177,32 +3055,42 @@ var InteractionDispatcher = class {
3177
3055
  this.isInitialized = true;
3178
3056
  const handlersDir = this.core.config.bot.interactions.path;
3179
3057
  if (!handlersDir) return;
3180
- this.logger.info(chalk.default.bold(handlersDir));
3181
3058
  const middlewareDir = (0, _seedcord_utils.hasKeys)(this.core.config.bot.interactions, ["middlewares"]) ? this.core.config.bot.interactions.middlewares : void 0;
3182
- if (middlewareDir) {
3183
- this.logger.info(`${chalk.default.bold(middlewareDir)} ${chalk.default.gray("(middlewares)")}`);
3184
- await this.loadMiddlewares(middlewareDir);
3059
+ this.loading = true;
3060
+ this.loadedHandlers.length = 0;
3061
+ this.loadedMiddlewares.length = 0;
3062
+ try {
3063
+ if (middlewareDir) await this.loadMiddlewares(middlewareDir);
3064
+ await this.loadHandlers(handlersDir);
3065
+ } finally {
3066
+ this.loading = false;
3185
3067
  }
3186
- await this.loadHandlers(handlersDir);
3187
3068
  this.attachToClient();
3188
- this.logger.info(`${chalk.default.bold.green("Loaded interaction handlers:")}`);
3189
- this.logger.utils.list([
3190
- `${chalk.default.magenta.bold(this.middlewares.length)} middlewares`,
3191
- `${chalk.default.magenta.bold(this.slashMap.size)} slash commands`,
3192
- `${chalk.default.magenta.bold(this.buttonMap.size)} buttons`,
3193
- `${chalk.default.magenta.bold(this.modalMap.size)} modals`,
3194
- `${chalk.default.magenta.bold(this.stringSelectMap.size)} string selects`,
3195
- `${chalk.default.magenta.bold(this.userSelectMap.size)} user selects`,
3196
- `${chalk.default.magenta.bold(this.roleSelectMap.size)} role selects`,
3197
- `${chalk.default.magenta.bold(this.channelSelectMap.size)} channel selects`,
3198
- `${chalk.default.magenta.bold(this.mentionableSelectMap.size)} mentionable selects`,
3199
- `${chalk.default.magenta.bold(this.messageContextMenuMap.size)} message context menus`,
3200
- `${chalk.default.magenta.bold(this.userContextMenuMap.size)} user context menus`,
3201
- `${chalk.default.magenta.bold(this.autocompleteMap.size)} autocomplete`
3202
- ]);
3069
+ this.reportLoad();
3070
+ }
3071
+ reportLoad() {
3072
+ const { utils } = this.logger;
3073
+ utils.summary("Loaded", {
3074
+ "interaction handlers": this.loadedHandlers.length,
3075
+ middlewares: this.loadedMiddlewares.length
3076
+ });
3077
+ if (this.loadedMiddlewares.length > 0) utils.block("Loaded middlewares", utils.entries(this.loadedMiddlewares));
3078
+ utils.block("Loaded interaction handlers", [...utils.entries(this.loadedHandlers), ...utils.counts({
3079
+ slash: this.slashMap.size,
3080
+ buttons: this.buttonMap.size,
3081
+ modals: this.modalMap.size,
3082
+ "string selects": this.stringSelectMap.size,
3083
+ "user selects": this.userSelectMap.size,
3084
+ "role selects": this.roleSelectMap.size,
3085
+ "channel selects": this.channelSelectMap.size,
3086
+ "mentionable selects": this.mentionableSelectMap.size,
3087
+ "message menus": this.messageContextMenuMap.size,
3088
+ "user menus": this.userContextMenuMap.size,
3089
+ autocomplete: this.autocompleteMap.size
3090
+ })]);
3203
3091
  }
3204
3092
  async loadHandlers(dir) {
3205
- await (0, _seedcord_utils.traverseDirectory)(dir, (fullPath, relativePath, imported) => {
3093
+ await (0, _seedcord_utils_node.traverseDirectory)(dir, (fullPath, relativePath, imported) => {
3206
3094
  for (const val of Object.values(imported)) {
3207
3095
  if (!this.isHandlerClass(val)) continue;
3208
3096
  this.registerHandler(val, relativePath);
@@ -3211,7 +3099,7 @@ var InteractionDispatcher = class {
3211
3099
  }, this.logger);
3212
3100
  }
3213
3101
  async loadMiddlewares(dir) {
3214
- await (0, _seedcord_utils.traverseDirectory)(dir, (fullPath, relativePath, imported) => {
3102
+ await (0, _seedcord_utils_node.traverseDirectory)(dir, (fullPath, relativePath, imported) => {
3215
3103
  for (const val of Object.values(imported)) {
3216
3104
  if (!this.isMiddlewareClass(val)) continue;
3217
3105
  this.registerMiddleware(val, relativePath);
@@ -3229,7 +3117,14 @@ var InteractionDispatcher = class {
3229
3117
  priority: metadata.priority
3230
3118
  });
3231
3119
  this.middlewares.sort((a, b) => a.priority - b.priority);
3232
- this.logger.utils.registration(`${middlewareCtor.name} ${chalk.default.gray(`(${metadata.priority})`)}`, relativePath, "middleware");
3120
+ if (this.loading) {
3121
+ this.loadedMiddlewares.push({
3122
+ name: `${middlewareCtor.name} (${metadata.priority})`,
3123
+ from: (0, _seedcord_utils.formatFilePath)(relativePath)
3124
+ });
3125
+ return;
3126
+ }
3127
+ this.logger.utils.registration(`${middlewareCtor.name} ${_seedcord_logger.paint.mute(`(${metadata.priority})`)}`, relativePath, "middleware");
3233
3128
  }
3234
3129
  isHandlerClass(obj) {
3235
3130
  if (typeof obj !== "function") return false;
@@ -3253,9 +3148,15 @@ var InteractionDispatcher = class {
3253
3148
  ]);
3254
3149
  writes.push([map, route]);
3255
3150
  }
3256
- this.logger.utils.registration(handlerClass.name, (0, _seedcord_utils.formatFilePath)(relativePath));
3257
3151
  }
3152
+ if (writes.length === 0) return;
3258
3153
  for (const [map, route] of writes) map.set(route, handlerClass);
3154
+ const from = (0, _seedcord_utils.formatFilePath)(relativePath);
3155
+ if (this.loading) this.loadedHandlers.push({
3156
+ name: handlerClass.name,
3157
+ from
3158
+ });
3159
+ else this.logger.utils.registration(handlerClass.name, from);
3259
3160
  }
3260
3161
  /** @internal For use in dev mode */
3261
3162
  async onHmr(event) {
@@ -3283,7 +3184,7 @@ var InteractionDispatcher = class {
3283
3184
  this.core.bot.client.on(discord_js.Events.InteractionCreate, (interaction) => {
3284
3185
  this.core.bot.emitSafe("any:interaction", interaction);
3285
3186
  this.handleInteraction(interaction).catch((err) => {
3286
- this.logger.error(`[${chalk.default.bold.red("UNHANDLED ERROR AT ROOT")}] ${err.name}`, err.stack);
3187
+ this.logger.error(`[${_seedcord_logger.paint.coral.bold("UNHANDLED ERROR AT ROOT")}] ${err.name}`, err.stack);
3287
3188
  this.core.bot.emit("error:unhandled:interaction", err);
3288
3189
  });
3289
3190
  });
@@ -3300,10 +3201,10 @@ var InteractionDispatcher = class {
3300
3201
  if (!interaction.isAutocomplete()) for (const { ctor } of this.middlewares) await new ctor(interaction, this.core).execute();
3301
3202
  let HandlerCtor = getHandler(key);
3302
3203
  if (!HandlerCtor) {
3303
- this.logger.warn(`No handler found for key ${chalk.default.bold.cyan(key)}. Falling back to UnhandledEvent.`);
3204
+ this.logger.warn(`No handler found for key ${_seedcord_logger.paint.sky.bold(key)}. Falling back to UnhandledEvent.`);
3304
3205
  HandlerCtor = UnhandledEvent;
3305
3206
  }
3306
- this.logger.debug(`Processing ${chalk.default.bold.green(key)} with ${chalk.default.gray(HandlerCtor.name)}`);
3207
+ this.logger.debug(`Processing ${_seedcord_logger.paint.mint.bold(key)} with ${_seedcord_logger.paint.mute(HandlerCtor.name)}`);
3307
3208
  const dispatch = new _seedcord_core.DispatchContext((0, _seedcord_core_internal.routeIdOf)(HandlerCtor));
3308
3209
  const handler = new HandlerCtor(interaction, this.core, dispatch);
3309
3210
  if (!interaction.isAutocomplete()) await (0, _seedcord_core_internal.runHandlerGates)(HandlerCtor, interactionGateContext(interaction, this.core));
@@ -3386,7 +3287,7 @@ var InteractionDispatcher = class {
3386
3287
  async handleAutocomplete(interaction) {
3387
3288
  const route = slashRouteOf(interaction);
3388
3289
  if (!this.autocompleteMap.has(route)) {
3389
- this.logger.warn(`No autocomplete handler for ${chalk.default.bold.cyan(route)}.`);
3290
+ this.logger.warn(`No autocomplete handler for ${_seedcord_logger.paint.sky.bold(route)}.`);
3390
3291
  await interaction.respond([]);
3391
3292
  return;
3392
3293
  }
@@ -3418,7 +3319,7 @@ function __decorate(decorators, target, key, desc) {
3418
3319
  */
3419
3320
  var Bot = class extends Plugin {
3420
3321
  /** @internal */
3421
- logger = new _seedcord_services.Logger("Bot");
3322
+ logger = new _seedcord_logger.Logger("Bot");
3422
3323
  isInitialized = false;
3423
3324
  _client;
3424
3325
  interactions;
@@ -3503,47 +3404,7 @@ var Bot = class extends Plugin {
3503
3404
  this.logger.error(`listener for ${String(event)} threw`, error);
3504
3405
  }
3505
3406
  };
3506
- __decorate([(0, envapt.Envapt)("DISCORD_BOT_TOKEN", { converter: (raw) => (0, _seedcord_errors_internal.validateDiscordToken)(raw) }), __decorateMetadata("design:type", String)], Bot.prototype, "botToken", void 0);
3507
-
3508
- //#endregion
3509
- //#region src/hmr/HmrManager.ts
3510
- var HmrManager = class {
3511
- logger = new _seedcord_services.Logger("HMR", { channel: "hmr" });
3512
- listeners = /* @__PURE__ */ new Set();
3513
- constructor() {}
3514
- /** @internal */
3515
- init() {
3516
- if (!{}.hot) return;
3517
- setDevChannel((0, _seedcord_types_internal.wrapHot)({}.hot));
3518
- if (envapt.Envapter.isDevelopment || envapt.Envapter.isTest) {
3519
- this.logger.info("Enabled");
3520
- getDevChannel()?.on("seedcord:hmr", (payload) => {
3521
- const affected = payload.affectedModules?.length ?? 0;
3522
- this.logger.info(`${chalk.default.bold("1")} module changed, ${chalk.default.bold(affected)} affected modules`);
3523
- if (payload.affectedModules) this.logger.utils.list(payload.affectedModules.map((mod) => (0, _seedcord_utils.formatFilePath)(mod)), "Affected modules: ");
3524
- this.handleUpdate(payload);
3525
- });
3526
- }
3527
- }
3528
- /** @internal */
3529
- register(listener) {
3530
- this.listeners.add(listener);
3531
- }
3532
- /** @internal */
3533
- unregister(listener) {
3534
- this.listeners.delete(listener);
3535
- }
3536
- async handleUpdate(event) {
3537
- const promises = [...this.listeners].map(async (listener) => {
3538
- try {
3539
- await listener.onHmr(event);
3540
- } catch (error) {
3541
- this.logger.error(`Error handling HMR update in ${chalk.default.bold(listener.name)}: `, error);
3542
- }
3543
- });
3544
- await Promise.all(promises);
3545
- }
3546
- };
3407
+ __decorate([(0, envapt_legacy.Envapt)("DISCORD_BOT_TOKEN", { converter: (raw) => (0, _seedcord_errors_internal.validateDiscordToken)(raw) }), __decorateMetadata("design:type", String)], Bot.prototype, "botToken", void 0);
3547
3408
 
3548
3409
  //#endregion
3549
3410
  //#region src/subscribers/bases/webhookHelpers.ts
@@ -3610,7 +3471,7 @@ let HandledException = class HandledException extends WebhookLog {
3610
3471
  }
3611
3472
  }
3612
3473
  };
3613
- __decorate([(0, envapt.Envapt)("HANDLED_EXCEPTION_WEBHOOK_URL", { converter: (raw) => webhookUrlValidator$1(raw) }), __decorateMetadata("design:type", String)], HandledException, "handledExceptionWebhookUrl", void 0);
3474
+ __decorate([(0, envapt_legacy.Envapt)("HANDLED_EXCEPTION_WEBHOOK_URL", { converter: (raw) => webhookUrlValidator$1(raw) }), __decorateMetadata("design:type", String)], HandledException, "handledExceptionWebhookUrl", void 0);
3614
3475
  HandledException = _HandledException = __decorate([Subscribe("handledException")], HandledException);
3615
3476
  var HandledExceptionContainer = class extends _seedcord_core.BuilderComponent {
3616
3477
  constructor(data) {
@@ -3680,7 +3541,7 @@ let UnknownException = class UnknownException extends WebhookLog {
3680
3541
  }
3681
3542
  }
3682
3543
  };
3683
- __decorate([(0, envapt.Envapt)("UNKNOWN_EXCEPTION_WEBHOOK_URL", { converter: (raw) => webhookUrlValidator(raw) }), __decorateMetadata("design:type", String)], UnknownException, "unknownExceptionWebhookUrl", void 0);
3544
+ __decorate([(0, envapt_legacy.Envapt)("UNKNOWN_EXCEPTION_WEBHOOK_URL", { converter: (raw) => webhookUrlValidator(raw) }), __decorateMetadata("design:type", String)], UnknownException, "unknownExceptionWebhookUrl", void 0);
3684
3545
  UnknownException = _UnknownException = __decorate([Subscribe("unknownException")], UnknownException);
3685
3546
  var UnhandledErrorContainer = class extends _seedcord_core.BuilderComponent {
3686
3547
  constructor(data) {
@@ -3719,7 +3580,7 @@ var UnhandledErrorContainer = class extends _seedcord_core.BuilderComponent {
3719
3580
  */
3720
3581
  var Bus = class extends Plugin {
3721
3582
  core;
3722
- logger = new _seedcord_services.Logger("Subscribers");
3583
+ logger = new _seedcord_logger.Logger("Subscribers");
3723
3584
  /** @internal */
3724
3585
  name = "Subscribers";
3725
3586
  isInitialized = false;
@@ -3731,7 +3592,7 @@ var Bus = class extends Plugin {
3731
3592
  this.core = core;
3732
3593
  if (this.core.config.subscribers.path) {
3733
3594
  if (!envapt.Envapter.isDevelopment && !envapt.Envapter.isTest) return;
3734
- this.hmrHandler = new HmrModuleHandler({
3595
+ this.hmrHandler = new _seedcord_core_hmr.HmrModuleHandler({
3735
3596
  handlersDir: this.core.config.subscribers.path,
3736
3597
  isHandler: this.isSubscriber.bind(this),
3737
3598
  registerHandler: this.registerSubscriber.bind(this),
@@ -3764,7 +3625,7 @@ var Bus = class extends Plugin {
3764
3625
  if (this.hmrHandler) await this.hmrHandler.handle(event);
3765
3626
  }
3766
3627
  async loadSubscribers(dir) {
3767
- await (0, _seedcord_utils.traverseDirectory)(dir, (fullPath, relativePath, imported) => {
3628
+ await (0, _seedcord_utils_node.traverseDirectory)(dir, (fullPath, relativePath, imported) => {
3768
3629
  for (const exportName of Object.keys(imported)) {
3769
3630
  const val = imported[exportName];
3770
3631
  if (this.isSubscriber(val)) {
@@ -3835,7 +3696,7 @@ var Bus = class extends Plugin {
3835
3696
  //#endregion
3836
3697
  //#region src/version.ts
3837
3698
  /** Package version */
3838
- const version = "0.1.0-next.1";
3699
+ const version = "0.1.0-next.2";
3839
3700
 
3840
3701
  //#endregion
3841
3702
  //#region src/Seedcord.ts
@@ -3854,6 +3715,8 @@ var Seedcord = class Seedcord extends Pluggable {
3854
3715
  /** @internal */
3855
3716
  version = version;
3856
3717
  static isInstantiated = false;
3718
+ healthCheck;
3719
+ hmrManager;
3857
3720
  /** @see {@link CoordinatedShutdown} */
3858
3721
  shutdown;
3859
3722
  /** @see {@link CoordinatedStartup} */
@@ -3864,10 +3727,6 @@ var Seedcord = class Seedcord extends Pluggable {
3864
3727
  bot;
3865
3728
  /** @see {@link IRateLimiter} */
3866
3729
  rateLimiter;
3867
- /** @see {@link HealthCheck} */
3868
- healthCheck;
3869
- /** @see {@link HmrManager} */
3870
- hmrManager;
3871
3730
  /**
3872
3731
  * Creates a new Seedcord instance
3873
3732
  *
@@ -3881,10 +3740,11 @@ var Seedcord = class Seedcord extends Pluggable {
3881
3740
  const startup = new _seedcord_services.CoordinatedStartup();
3882
3741
  super(shutdown, startup);
3883
3742
  this.config = config;
3743
+ (0, _seedcord_logger_node.installNodeDefaults)(config.logger);
3884
3744
  (0, _seedcord_core_internal.setBotColor)(config.botColor);
3885
3745
  this.shutdown = shutdown;
3886
3746
  this.startup = startup;
3887
- this.hmrManager = new HmrManager();
3747
+ this.hmrManager = new _seedcord_core_internal.HmrManager();
3888
3748
  this.hmrManager.init();
3889
3749
  this.bus = new Bus(this);
3890
3750
  this.bot = new Bot(this);
@@ -3892,14 +3752,14 @@ var Seedcord = class Seedcord extends Pluggable {
3892
3752
  this.healthCheck = new _seedcord_services.HealthCheck(this.shutdown, config.healthCheck);
3893
3753
  this.registerStartupTasks();
3894
3754
  }
3895
- /** @internal */
3755
+ /** The bot's discord username, populated after login. */
3756
+ get username() {
3757
+ return this.bot.client.user?.username;
3758
+ }
3896
3759
  static reset() {
3897
3760
  Seedcord.isInstantiated = false;
3761
+ _seedcord_logger.LoggerChannelRegistry.instance.reset();
3898
3762
  }
3899
- /**
3900
- * Registers default startup tasks
3901
- * @internal
3902
- */
3903
3763
  registerStartupTasks() {
3904
3764
  if (envapt.Envapter.isDevelopment || envapt.Envapter.isTest) this.registerHmrAwareModules();
3905
3765
  this.startup.addTask(_seedcord_services.StartupPhase.Configuration, "Bus Initialization", async () => {
@@ -3951,7 +3811,6 @@ exports.Emojis = Emojis;
3951
3811
  exports.EventHandler = EventHandler;
3952
3812
  exports.EventMiddleware = EventMiddleware;
3953
3813
  exports.Gated = Gated;
3954
- exports.HmrModuleHandler = HmrModuleHandler;
3955
3814
  exports.IgnoreBots = IgnoreBots;
3956
3815
  exports.InteractionHandler = InteractionHandler;
3957
3816
  exports.InteractionMiddleware = InteractionMiddleware;
@@ -4017,6 +3876,13 @@ Object.keys(_seedcord_event_emitter).forEach(function (k) {
4017
3876
  });
4018
3877
  });
4019
3878
 
3879
+ Object.keys(_seedcord_logger).forEach(function (k) {
3880
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
3881
+ enumerable: true,
3882
+ get: function () { return _seedcord_logger[k]; }
3883
+ });
3884
+ });
3885
+
4020
3886
  Object.keys(_seedcord_rate_limiter).forEach(function (k) {
4021
3887
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
4022
3888
  enumerable: true,