seedcord 0.1.0 → 0.2.0

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
@@ -1,15 +1,13 @@
1
1
  'use strict';
2
2
 
3
3
  require('reflect-metadata');
4
- var chalk6 = require('chalk');
4
+ var services = require('@seedcord/services');
5
+ var chalk2 = require('chalk');
5
6
  var discord_js = require('discord.js');
6
7
  var envapt = require('envapt');
7
- var promises = require('fs/promises');
8
- var path = require('path');
9
- var winston = require('winston');
8
+ var utils = require('@seedcord/utils');
10
9
  var crypto2 = require('crypto');
11
10
  var events = require('events');
12
- var http = require('http');
13
11
 
14
12
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
15
13
 
@@ -31,12 +29,74 @@ function _interopNamespace(e) {
31
29
  return Object.freeze(n);
32
30
  }
33
31
 
34
- var chalk6__default = /*#__PURE__*/_interopDefault(chalk6);
35
- var path__namespace = /*#__PURE__*/_interopNamespace(path);
32
+ var chalk2__default = /*#__PURE__*/_interopDefault(chalk2);
36
33
  var crypto2__namespace = /*#__PURE__*/_interopNamespace(crypto2);
37
34
 
38
35
  var __defProp = Object.defineProperty;
39
36
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
37
+ var Plugin = class {
38
+ static {
39
+ __name(this, "Plugin");
40
+ }
41
+ pluggable;
42
+ constructor(pluggable) {
43
+ this.pluggable = pluggable;
44
+ }
45
+ };
46
+ var Pluggable = class _Pluggable {
47
+ static {
48
+ __name(this, "Pluggable");
49
+ }
50
+ isInitialized = false;
51
+ shutdown;
52
+ startup;
53
+ static PLUGIN_INIT_TIMEOUT_MS = 15e3;
54
+ constructor(shutdown, startup) {
55
+ this.shutdown = shutdown;
56
+ this.startup = startup;
57
+ }
58
+ async init() {
59
+ if (this.isInitialized) return this;
60
+ await this.startup.run();
61
+ this.isInitialized = true;
62
+ return this;
63
+ }
64
+ /**
65
+ * Attaches a plugin to this instance
66
+ *
67
+ * Plugins provide external functionality and are initialized during the specified startup phase.
68
+ * The plugin instance becomes available as a property in `core` wherever it's available.
69
+ *
70
+ * Make sure to augment the {@link Core} interface with the plugin type to ensure TypeScript recognizes it and provides intellisense.
71
+ *
72
+ * @typeParam Key - The property name for accessing the plugin
73
+ * @typeParam Ctor - The plugin constructor type
74
+ * @param key - Property name to access the plugin instance
75
+ * @param Plugin - Plugin constructor class
76
+ * @param startupPhase - When during startup to initialize this plugin ({@link StartupPhase})
77
+ * @param args - Additional arguments to pass to the plugin constructor
78
+ * @returns This instance with the plugin attached as a typed property
79
+ * @throws An {@link Error} When called after initialization or if key already exists
80
+ * @example
81
+ * ```typescript
82
+ * seedcord.attach('db', Mongo, StartupPhase.Configuration, { uri: 'mongodb://...', name: 'seedcord', dir: ... })
83
+ * ```
84
+ */
85
+ attach(key, Plugin2, startupPhase, ...args) {
86
+ if (this.isInitialized) throw new Error("Cannot attach a plugin after initialization.");
87
+ if (this[key]) throw new Error(`Plugin with key "${key}" already exists.`);
88
+ const instance = new Plugin2(this, ...args);
89
+ const entry = {
90
+ [key]: instance
91
+ };
92
+ this.startup.addTask(startupPhase, `Plugin:${key}`, async () => {
93
+ instance.logger.info(chalk2__default.default.bold("Initializing"));
94
+ await instance.init();
95
+ instance.logger.info(chalk2__default.default.bold("Initialized"));
96
+ }, _Pluggable.PLUGIN_INIT_TIMEOUT_MS);
97
+ return Object.assign(this, entry);
98
+ }
99
+ };
40
100
  function _ts_decorate(decorators, target, key, desc) {
41
101
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
42
102
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -48,54 +108,6 @@ function _ts_metadata(k, v) {
48
108
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
49
109
  }
50
110
  __name(_ts_metadata, "_ts_metadata");
51
- var Globals = class extends envapt.Envapter {
52
- static {
53
- __name(this, "Globals");
54
- }
55
- static botToken;
56
- // Healthcheck
57
- static healthCheckPort;
58
- static healthCheckPath;
59
- // Coordinated Shutdown
60
- static shutdownIsEnabled;
61
- // Unknown Exception Webhook URL
62
- static unknownExceptionWebhookUrl;
63
- // Variables
64
- /** Default color for bot embeds - can be overridden by setting Globals.botColor */
65
- static botColor = this.isProduction ? "#fe565a" : "#3fa045";
66
- };
67
- _ts_decorate([
68
- envapt.Envapt("DISCORD_BOT_TOKEN", {
69
- fallback: void 0
70
- }),
71
- _ts_metadata("design:type", String)
72
- ], Globals, "botToken", void 0);
73
- _ts_decorate([
74
- envapt.Envapt("HEALTH_CHECK_PORT", {
75
- fallback: 6956
76
- }),
77
- _ts_metadata("design:type", Number)
78
- ], Globals, "healthCheckPort", void 0);
79
- _ts_decorate([
80
- envapt.Envapt("HEALTH_CHECK_PATH", {
81
- fallback: "/healthcheck"
82
- }),
83
- _ts_metadata("design:type", String)
84
- ], Globals, "healthCheckPath", void 0);
85
- _ts_decorate([
86
- envapt.Envapt("SHUTDOWN_IS_ENABLED", {
87
- fallback: false
88
- }),
89
- _ts_metadata("design:type", Boolean)
90
- ], Globals, "shutdownIsEnabled", void 0);
91
- _ts_decorate([
92
- envapt.Envapt("UNKNOWN_EXCEPTION_WEBHOOK_URL", {
93
- fallback: void 0
94
- }),
95
- _ts_metadata("design:type", String)
96
- ], Globals, "unknownExceptionWebhookUrl", void 0);
97
-
98
- // src/interfaces/Components.ts
99
111
  var BuilderTypes = {
100
112
  command: discord_js.SlashCommandBuilder,
101
113
  embed: discord_js.EmbedBuilder,
@@ -109,7 +121,13 @@ var BuilderTypes = {
109
121
  modal: discord_js.ModalBuilder,
110
122
  context_menu: discord_js.ContextMenuCommandBuilder,
111
123
  subcommand: discord_js.SlashCommandSubcommandBuilder,
112
- group: discord_js.SlashCommandSubcommandGroupBuilder
124
+ group: discord_js.SlashCommandSubcommandGroupBuilder,
125
+ container: discord_js.ContainerBuilder,
126
+ text_display: discord_js.TextDisplayBuilder,
127
+ file: discord_js.FileBuilder,
128
+ media: discord_js.MediaGalleryBuilder,
129
+ section: discord_js.SectionBuilder,
130
+ separator: discord_js.SeparatorBuilder
113
131
  };
114
132
  var RowTypes = {
115
133
  button: discord_js.ActionRowBuilder,
@@ -143,6 +161,20 @@ var BaseComponent = class BaseComponent2 {
143
161
  get instance() {
144
162
  return this._component;
145
163
  }
164
+ /**
165
+ * Builds a customId string for interactive components
166
+ *
167
+ * Creates customIds in the format "prefix:arg1-arg2-arg3" for buttons, modals, etc.
168
+ * Arguments are joined with hyphens and separated from prefix with a colon.
169
+ *
170
+ * @param prefix - The route prefix that handlers will match against
171
+ * @param args - Additional arguments to encode in the customId
172
+ * @returns Formatted customId string
173
+ */
174
+ buildCustomId(prefix, ...args) {
175
+ if (args.length === 0) return prefix;
176
+ return `${prefix}:${args.join("-")}`;
177
+ }
146
178
  };
147
179
  var BuilderComponent = class extends BaseComponent {
148
180
  static {
@@ -151,7 +183,7 @@ var BuilderComponent = class extends BaseComponent {
151
183
  constructor(type) {
152
184
  const ComponentClass = BuilderTypes[type];
153
185
  super(ComponentClass);
154
- if (this.instance instanceof discord_js.EmbedBuilder) this.instance.setColor(Globals.botColor);
186
+ if (this.instance instanceof discord_js.EmbedBuilder) this.instance.setColor(this.botColor);
155
187
  if (this.instance instanceof discord_js.SlashCommandBuilder || this.instance instanceof discord_js.ContextMenuCommandBuilder) {
156
188
  this.instance.setContexts(discord_js.InteractionContextType.Guild);
157
189
  }
@@ -159,21 +191,13 @@ var BuilderComponent = class extends BaseComponent {
159
191
  get component() {
160
192
  return this.instance;
161
193
  }
162
- /**
163
- * Builds a customId string for interactive components
164
- *
165
- * Creates customIds in the format "prefix:arg1-arg2-arg3" for buttons, modals, etc.
166
- * Arguments are joined with hyphens and separated from prefix with a colon.
167
- *
168
- * @param prefix - The route prefix that handlers will match against
169
- * @param args - Additional arguments to encode in the customId
170
- * @returns Formatted customId string
171
- */
172
- buildCustomId(prefix, ...args) {
173
- if (args.length === 0) return prefix;
174
- return `${prefix}:${args.join("-")}`;
175
- }
176
194
  };
195
+ _ts_decorate([
196
+ envapt.Envapt("DEFAULT_BOT_COLOR", {
197
+ fallback: "Default"
198
+ }),
199
+ _ts_metadata("design:type", typeof ColorResolvable === "undefined" ? Object : ColorResolvable)
200
+ ], BuilderComponent.prototype, "botColor", void 0);
177
201
  var RowComponent = class extends BaseComponent {
178
202
  static {
179
203
  __name(this, "RowComponent");
@@ -248,387 +272,6 @@ var CustomError = class extends Error {
248
272
  }
249
273
  };
250
274
 
251
- // src/bot/errors/Database.ts
252
- var DatabaseError = class extends CustomError {
253
- static {
254
- __name(this, "DatabaseError");
255
- }
256
- uuid;
257
- _emit = true;
258
- /**
259
- * Creates a new DatabaseError.
260
- *
261
- * @param message - The error message describing what went wrong
262
- * @param uuid - A unique identifier for this specific error instance
263
- */
264
- constructor(message, uuid) {
265
- super(message), this.uuid = uuid;
266
- this.name = "DatabaseError";
267
- this.response.setTitle("Database Error").setDescription(`An error occurred while interacting with the database.
268
- ### UUID: \`${this.uuid}\``);
269
- }
270
- };
271
- var Logger = class _Logger {
272
- static {
273
- __name(this, "Logger");
274
- }
275
- static instances = /* @__PURE__ */ new Map();
276
- static instance(prefix) {
277
- let instance = this.instances.get(prefix);
278
- if (!instance) {
279
- instance = new _Logger(prefix);
280
- this.instances.set(prefix, instance);
281
- }
282
- return instance;
283
- }
284
- constructor(transportName) {
285
- const consoleTransport = this.createConsoleTransport(transportName);
286
- this.initializeLogger(consoleTransport);
287
- }
288
- getFormatCustomizations() {
289
- const padding = 7;
290
- return [
291
- winston.format.errors({
292
- stack: true
293
- }),
294
- winston.format.splat(),
295
- winston.format.colorize({
296
- level: true
297
- }),
298
- winston.format.timestamp({
299
- format: "D MMM, hh:mm:ss a"
300
- }),
301
- winston.format.printf((info) => {
302
- const ts = String(info.timestamp ?? "");
303
- const lvl = String(info.level).padEnd(padding);
304
- const lbl = String(info.label ?? "");
305
- const msg = String(info.message ?? "");
306
- const base = `${ts} [${lvl}]: ${lbl} - ${msg}`;
307
- const splatSym = Symbol.for("splat");
308
- const raw = info[splatSym];
309
- const extras = Array.isArray(raw) ? raw : [];
310
- const cleaned = extras.filter((x) => !(x instanceof Error)).filter((x) => {
311
- if (!x) return false;
312
- if (typeof x !== "object") return true;
313
- return Object.keys(x).length > 0;
314
- });
315
- let rendered = base;
316
- if (typeof info.stack === "string") {
317
- rendered += `
318
- ${String(info.stack)}`;
319
- }
320
- if (cleaned.length) {
321
- const parts = [];
322
- for (const x of cleaned) {
323
- if (typeof x === "string") parts.push(x);
324
- else {
325
- try {
326
- parts.push(JSON.stringify(x, null, 2));
327
- } catch {
328
- parts.push(String(x));
329
- }
330
- }
331
- }
332
- rendered += `
333
- ${parts.join(" ")}`;
334
- }
335
- return rendered;
336
- })
337
- ];
338
- }
339
- createConsoleTransport(transportName) {
340
- return new winston.transports.Console({
341
- format: winston.format.combine(winston.format.label({
342
- label: transportName
343
- }), ...this.getFormatCustomizations()),
344
- level: Globals.isDevelopment ? "silly" : Globals.isStaging ? "debug" : "info"
345
- });
346
- }
347
- initializeLogger(consoleTransport) {
348
- const transportsArray = [
349
- consoleTransport
350
- ];
351
- if (Globals.isDevelopment) {
352
- const maxSizeInMB = 10;
353
- transportsArray.push(new winston.transports.File({
354
- filename: "logs/application.log",
355
- level: "debug",
356
- format: winston.format.combine(winston.format.uncolorize(), winston.format.errors({
357
- stack: true
358
- }), winston.format.timestamp(), winston.format.json({
359
- bigint: true,
360
- space: 2
361
- })),
362
- maxsize: maxSizeInMB * 1024 * 1024,
363
- maxFiles: 5,
364
- tailable: true
365
- }));
366
- }
367
- this.logger = winston.createLogger({
368
- transports: transportsArray
369
- });
370
- }
371
- /**
372
- * Logs an error message with optional additional data.
373
- *
374
- * @param msg - The error message to log
375
- * @param args - Additional data to include in the log entry
376
- */
377
- error(msg, ...args) {
378
- this.logger.error(msg, ...args);
379
- }
380
- /**
381
- * Logs a warning message with optional additional data.
382
- *
383
- * @param msg - The warning message to log
384
- * @param args - Additional data to include in the log entry
385
- */
386
- warn(msg, ...args) {
387
- this.logger.warn(msg, ...args);
388
- }
389
- /**
390
- * Logs an informational message with optional additional data.
391
- *
392
- * @param msg - The informational message to log
393
- * @param args - Additional data to include in the log entry
394
- */
395
- info(msg, ...args) {
396
- this.logger.info(msg, ...args);
397
- }
398
- /**
399
- * Logs an HTTP-related message with optional additional data.
400
- *
401
- * @param msg - The HTTP message to log
402
- * @param args - Additional data to include in the log entry
403
- */
404
- http(msg, ...args) {
405
- this.logger.http(msg, ...args);
406
- }
407
- /**
408
- * Logs a verbose message with optional additional data.
409
- *
410
- * @param msg - The verbose message to log
411
- * @param args - Additional data to include in the log entry
412
- */
413
- verbose(msg, ...args) {
414
- this.logger.verbose(msg, ...args);
415
- }
416
- /**
417
- * Logs a debug message with optional additional data.
418
- *
419
- * @param msg - The debug message to log
420
- * @param args - Additional data to include in the log entry
421
- */
422
- debug(msg, ...args) {
423
- this.logger.debug(msg, ...args);
424
- }
425
- /**
426
- * Logs a silly/trace level message with optional additional data.
427
- *
428
- * @param msg - The silly message to log
429
- * @param args - Additional data to include in the log entry
430
- */
431
- silly(msg, ...args) {
432
- this.logger.silly(msg, ...args);
433
- }
434
- /**
435
- * Static method to log an error message with a specific prefix.
436
- * Creates or retrieves a logger instance for the given prefix.
437
- *
438
- * @param prefix - The logger prefix/label to use
439
- * @param msg - The error message to log
440
- * @param args - Additional data to include in the log entry
441
- */
442
- static Error(prefix, msg, ...args) {
443
- const logger = this.instance(prefix);
444
- logger.error(msg, ...args);
445
- }
446
- /**
447
- * Static method to log an informational message with a specific prefix.
448
- * Creates or retrieves a logger instance for the given prefix.
449
- *
450
- * @param prefix - The logger prefix/label to use
451
- * @param msg - The informational message to log
452
- * @param args - Additional data to include in the log entry
453
- */
454
- static Info(prefix, msg, ...args) {
455
- const logger = this.instance(prefix);
456
- logger.info(msg, ...args);
457
- }
458
- /**
459
- * Static method to log a warning message with a specific prefix.
460
- * Creates or retrieves a logger instance for the given prefix.
461
- *
462
- * @param prefix - The logger prefix/label to use
463
- * @param msg - The warning message to log
464
- * @param args - Additional data to include in the log entry
465
- */
466
- static Warn(prefix, msg, ...args) {
467
- const logger = this.instance(prefix);
468
- logger.warn(msg, ...args);
469
- }
470
- /**
471
- * Static method to log a debug message with a specific prefix.
472
- * Creates or retrieves a logger instance for the given prefix.
473
- *
474
- * @param prefix - The logger prefix/label to use
475
- * @param msg - The debug message to log
476
- * @param args - Additional data to include in the log entry
477
- */
478
- static Debug(prefix, msg, ...args) {
479
- const logger = this.instance(prefix);
480
- logger.debug(msg, ...args);
481
- }
482
- /**
483
- * Static method to log a silly/trace level message with a specific prefix.
484
- * Creates or retrieves a logger instance for the given prefix.
485
- *
486
- * @param prefix - The logger prefix/label to use
487
- * @param msg - The silly message to log
488
- * @param args - Additional data to include in the log entry
489
- */
490
- static Silly(prefix, msg, ...args) {
491
- const logger = this.instance(prefix);
492
- logger.silly(msg, ...args);
493
- }
494
- };
495
-
496
- // src/library/Helpers.ts
497
- function numberFixer(num, decimalPlaces) {
498
- const factor = Math.pow(10, decimalPlaces);
499
- return Math.round((num + Number.EPSILON) * factor) / factor;
500
- }
501
- __name(numberFixer, "numberFixer");
502
- function percentage(num1, num2) {
503
- return Number((num1 / num2 * 100).toFixed(2));
504
- }
505
- __name(percentage, "percentage");
506
- function generateAsciiTable(data) {
507
- if (data.length === 0) return "";
508
- const firstRow = data[0];
509
- if (!firstRow || firstRow.length === 0) return "";
510
- let table = "";
511
- const columnWidths = [];
512
- for (let i = 0; i < firstRow.length; i++) {
513
- let maxWidth = 0;
514
- for (const row of data) {
515
- const cell = row[i];
516
- if (cell !== void 0) maxWidth = Math.max(maxWidth, cell.length);
517
- }
518
- columnWidths.push(maxWidth);
519
- }
520
- const createLine = /* @__PURE__ */ __name((char, left, intersect, right) => {
521
- let line = left;
522
- columnWidths.forEach((width, index) => {
523
- line += char.repeat(width + 2);
524
- if (index < columnWidths.length - 1) line += intersect;
525
- else line += right;
526
- });
527
- line += "\n";
528
- return line;
529
- }, "createLine");
530
- table += createLine("\u2550", "\u2554", "\u2566", "\u2557");
531
- data.forEach((row, rowIndex) => {
532
- table += "\u2551";
533
- row.forEach((cell, columnIndex) => {
534
- const columnWidth = columnWidths[columnIndex];
535
- if (columnWidth !== void 0) table += ` ${cell.padEnd(columnWidth)} \u2551`;
536
- });
537
- table += "\n";
538
- if (rowIndex < data.length - 1) table += createLine("\u2500", "\u2560", "\u256C", "\u2563");
539
- else table += createLine("\u2550", "\u255A", "\u2569", "\u255D");
540
- });
541
- return table;
542
- }
543
- __name(generateAsciiTable, "generateAsciiTable");
544
- function formatWord(word) {
545
- return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
546
- }
547
- __name(formatWord, "formatWord");
548
- function longestStringLength(arr) {
549
- return Math.max(...arr.map((el) => el.toString().length));
550
- }
551
- __name(longestStringLength, "longestStringLength");
552
- function currentTime() {
553
- return Math.floor(Date.now() / 1e3);
554
- }
555
- __name(currentTime, "currentTime");
556
- function ordinal(n) {
557
- const s = [
558
- "th",
559
- "st",
560
- "nd",
561
- "rd"
562
- ];
563
- const v = n % 100;
564
- const index = (v - 20) % 10;
565
- const suffix = s[index] ?? s[v] ?? s[0];
566
- if (!suffix) return `${n}th`;
567
- return `${n}${suffix}`;
568
- }
569
- __name(ordinal, "ordinal");
570
- function prettyDifference(numBefore, numAfter) {
571
- return (numAfter - numBefore > 0 ? `+${numAfter - numBefore}` : numAfter - numBefore).toString();
572
- }
573
- __name(prettyDifference, "prettyDifference");
574
- function isTsOrJsFile(entry) {
575
- return entry.isFile() && (entry.name.endsWith(".ts") || entry.name.endsWith(".js")) && !entry.name.endsWith(".d.ts") && !entry.name.endsWith(".map");
576
- }
577
- __name(isTsOrJsFile, "isTsOrJsFile");
578
- async function traverseDirectory(dir, callback) {
579
- let entries;
580
- try {
581
- entries = await promises.readdir(dir, {
582
- withFileTypes: true
583
- });
584
- } catch {
585
- Logger.Error("Failed to read directory", dir);
586
- entries = [];
587
- }
588
- for (const entry of entries) {
589
- const fullPath = path__namespace.join(dir, entry.name);
590
- const relativePath = path__namespace.relative(process.cwd(), fullPath);
591
- if (entry.isDirectory()) {
592
- await traverseDirectory(fullPath, callback);
593
- } else if (isTsOrJsFile(entry)) {
594
- const imported = await import(fullPath);
595
- await callback(fullPath, relativePath, imported);
596
- }
597
- }
598
- }
599
- __name(traverseDirectory, "traverseDirectory");
600
- function throwCustomError(error, message, CustomError2) {
601
- const uuid = crypto.randomUUID();
602
- Logger.Error("Throwing Custom Error", error.name);
603
- if (typeof CustomError2 === typeof DatabaseError) {
604
- const errorMessage = error instanceof Error ? error.message : message;
605
- throw new CustomError2(errorMessage, uuid);
606
- } else {
607
- if (error instanceof Error) {
608
- throw new CustomError2(`${message}: ${error.message ? error.message : error.toString()}`);
609
- } else {
610
- throw new CustomError2(message);
611
- }
612
- }
613
- }
614
- __name(throwCustomError, "throwCustomError");
615
- function prettify(key) {
616
- return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/_/g, " ").trim();
617
- }
618
- __name(prettify, "prettify");
619
- function fyShuffle(items) {
620
- const array = items.slice();
621
- for (let i = array.length - 1; i > 0; i--) {
622
- const j = Math.floor(Math.random() * (i + 1));
623
- [array[i], array[j]] = [
624
- array[j],
625
- array[i]
626
- ];
627
- }
628
- return array;
629
- }
630
- __name(fyShuffle, "fyShuffle");
631
-
632
275
  // src/bot/decorators/CommandRegisterable.ts
633
276
  var CommandMetadataKey = Symbol("command:metadata");
634
277
  function RegisterCommand(scope, guilds = []) {
@@ -650,7 +293,7 @@ var CommandRegistry = class {
650
293
  __name(this, "CommandRegistry");
651
294
  }
652
295
  core;
653
- logger = new Logger("Commands");
296
+ logger = new services.Logger("Commands");
654
297
  isInitialised = false;
655
298
  globalCommands = [];
656
299
  guildCommands = /* @__PURE__ */ new Map();
@@ -660,14 +303,14 @@ var CommandRegistry = class {
660
303
  async init() {
661
304
  if (this.isInitialised) return;
662
305
  this.isInitialised = true;
663
- this.logger.info(chalk6__default.default.bold(this.core.config.bot.commands.path));
306
+ this.logger.info(chalk2__default.default.bold(this.core.config.bot.commands.path));
664
307
  await this.loadCommands(this.core.config.bot.commands.path);
665
- this.logger.info(`${chalk6__default.default.bold.green("Loaded")}: ${chalk6__default.default.magenta.bold(this.globalCommands.length)} global, ${chalk6__default.default.magenta.bold(this.guildCommands.size)} guild groups`);
308
+ this.logger.info(`${chalk2__default.default.bold.green("Loaded")}: ${chalk2__default.default.magenta.bold(this.globalCommands.length)} global, ${chalk2__default.default.magenta.bold(this.guildCommands.size)} guild groups`);
666
309
  }
667
310
  async loadCommands(dir) {
668
- await traverseDirectory(dir, (_full, rel, mod) => {
311
+ await utils.traverseDirectory(dir, (_full, rel, mod) => {
669
312
  for (const exported of Object.values(mod)) if (this.isCommandClass(exported)) this.registerCommand(exported, rel);
670
- });
313
+ }, this.logger);
671
314
  }
672
315
  isCommandClass(obj) {
673
316
  if (typeof obj !== "function") return false;
@@ -681,24 +324,24 @@ var CommandRegistry = class {
681
324
  const commandType = comp instanceof discord_js.SlashCommandBuilder ? "slash command" : "context menu command";
682
325
  if (meta.scope === "global") {
683
326
  this.globalCommands.push(comp);
684
- this.logger.info(`${chalk6__default.default.italic("Registered")} ${chalk6__default.default.bold.yellow(ctor.name)} from ${chalk6__default.default.gray(rel)}`);
685
- this.logger.info(` \u2192 Global ${commandType}: ${chalk6__default.default.bold.cyan(comp.name)}`);
327
+ this.logger.info(`${chalk2__default.default.italic("Registered")} ${chalk2__default.default.bold.yellow(ctor.name)} from ${chalk2__default.default.gray(rel)}`);
328
+ this.logger.info(` \u2192 Global ${commandType}: ${chalk2__default.default.bold.cyan(comp.name)}`);
686
329
  } else {
687
330
  for (const g of meta.guilds) {
688
331
  const arr = this.guildCommands.get(g) ?? [];
689
332
  arr.push(comp);
690
333
  this.guildCommands.set(g, arr);
691
334
  }
692
- this.logger.info(`${chalk6__default.default.italic("Registered")} ${chalk6__default.default.bold.yellow(ctor.name)} from ${chalk6__default.default.gray(rel)}`);
693
- this.logger.info(` \u2192 Guild ${commandType}: ${chalk6__default.default.bold.cyan(comp.name)} for ${chalk6__default.default.magenta.bold(meta.guilds.length)} guild(s)`);
335
+ this.logger.info(`${chalk2__default.default.italic("Registered")} ${chalk2__default.default.bold.yellow(ctor.name)} from ${chalk2__default.default.gray(rel)}`);
336
+ this.logger.info(` \u2192 Guild ${commandType}: ${chalk2__default.default.bold.cyan(comp.name)} for ${chalk2__default.default.magenta.bold(meta.guilds.length)} guild(s)`);
694
337
  }
695
338
  }
696
339
  async setCommands() {
697
340
  if (this.globalCommands.length > 0) {
698
341
  await this.core.bot.client.application?.commands.set(this.globalCommands);
699
342
  const tag = this.globalCommands.length === 1 ? "command" : "commands";
700
- this.logger.info(`${chalk6__default.default.bold.green("Configured")} ${chalk6__default.default.magenta.bold(this.globalCommands.length)} global ${tag}`);
701
- this.logger.info(` \u2192 ${this.globalCommands.map((command) => chalk6__default.default.bold.cyan(command.name)).join(", ")}`);
343
+ this.logger.info(`${chalk2__default.default.bold.green("Configured")} ${chalk2__default.default.magenta.bold(this.globalCommands.length)} global ${tag}`);
344
+ this.logger.info(` \u2192 ${this.globalCommands.map((command) => chalk2__default.default.bold.cyan(command.name)).join(", ")}`);
702
345
  }
703
346
  for (const [guildId, commands] of this.guildCommands.entries()) {
704
347
  const guild = this.core.bot.client.guilds.cache.get(guildId);
@@ -708,8 +351,8 @@ var CommandRegistry = class {
708
351
  }
709
352
  await guild.commands.set(commands);
710
353
  const tag = commands.length === 1 ? "command" : "commands";
711
- this.logger.info(`${chalk6__default.default.bold.green("Configured")} ${chalk6__default.default.magenta.bold(commands.length)} ${tag} for guild ${chalk6__default.default.bold.yellow(guild.name)}`);
712
- this.logger.info(` \u2192 ${commands.map((command) => chalk6__default.default.bold.cyan(command.name)).join(", ")}`);
354
+ this.logger.info(`${chalk2__default.default.bold.green("Configured")} ${chalk2__default.default.magenta.bold(commands.length)} ${tag} for guild ${chalk2__default.default.bold.yellow(guild.name)}`);
355
+ this.logger.info(` \u2192 ${commands.map((command) => chalk2__default.default.bold.cyan(command.name)).join(", ")}`);
713
356
  }
714
357
  }
715
358
  };
@@ -814,7 +457,7 @@ var EventController = class {
814
457
  __name(this, "EventController");
815
458
  }
816
459
  core;
817
- logger = new Logger("Events");
460
+ logger = new services.Logger("Events");
818
461
  isInitialized = false;
819
462
  eventMap = /* @__PURE__ */ new Map();
820
463
  constructor(core) {
@@ -826,24 +469,24 @@ var EventController = class {
826
469
  }
827
470
  this.isInitialized = true;
828
471
  const handlersDir = this.core.config.bot.events.path;
829
- this.logger.info(chalk6__default.default.bold(handlersDir));
472
+ this.logger.info(chalk2__default.default.bold(handlersDir));
830
473
  await this.loadHandlers(handlersDir);
831
474
  this.attachToClient();
832
475
  const loadedEventsArray = [];
833
476
  this.eventMap.forEach((handlers, eventName) => {
834
- loadedEventsArray.push(`${chalk6__default.default.magenta.bold(handlers.length)} ${eventName}`);
477
+ loadedEventsArray.push(`${chalk2__default.default.magenta.bold(handlers.length)} ${eventName}`);
835
478
  });
836
- this.logger.info(`${chalk6__default.default.bold.green("Loaded")}: ${this.eventMap.size > 0 ? loadedEventsArray.join(", ") : "none"}`);
479
+ this.logger.info(`${chalk2__default.default.bold.green("Loaded")}: ${this.eventMap.size > 0 ? loadedEventsArray.join(", ") : "none"}`);
837
480
  }
838
481
  async loadHandlers(dir) {
839
- await traverseDirectory(dir, (_fullPath, relativePath, imported) => {
482
+ await utils.traverseDirectory(dir, (_fullPath, relativePath, imported) => {
840
483
  for (const val of Object.values(imported)) {
841
484
  if (this.isEventHandlerClass(val)) {
842
485
  this.registerHandler(val);
843
- this.logger.info(`${chalk6__default.default.italic("Registered")} ${chalk6__default.default.bold.yellow(val.name)} from ${chalk6__default.default.gray(relativePath)}`);
486
+ this.logger.info(`${chalk2__default.default.italic("Registered")} ${chalk2__default.default.bold.yellow(val.name)} from ${chalk2__default.default.gray(relativePath)}`);
844
487
  }
845
488
  }
846
- });
489
+ }, this.logger);
847
490
  }
848
491
  isEventHandlerClass(obj) {
849
492
  if (typeof obj !== "function") return false;
@@ -861,7 +504,7 @@ var EventController = class {
861
504
  }
862
505
  attachToClient() {
863
506
  for (const [eventName] of this.eventMap) {
864
- this.logger.debug(`Attaching ${chalk6__default.default.bold.green(eventName)} to ${chalk6__default.default.bold.yellow(this.core.bot.client.user?.username)}`);
507
+ this.logger.debug(`Attaching ${chalk2__default.default.bold.green(eventName)} to ${chalk2__default.default.bold.yellow(this.core.bot.client.user?.username)}`);
865
508
  this.core.bot.client.on(eventName, (...args) => {
866
509
  void (async () => {
867
510
  await this.processEvent(eventName, args);
@@ -874,7 +517,7 @@ var EventController = class {
874
517
  if (!handlerCtors || handlerCtors.length === 0) return;
875
518
  for (const HandlerCtor of handlerCtors) {
876
519
  try {
877
- this.logger.debug(`Processing ${chalk6__default.default.bold.green(eventName)} with ${chalk6__default.default.gray(HandlerCtor.name)}`);
520
+ this.logger.debug(`Processing ${chalk2__default.default.bold.green(eventName)} with ${chalk2__default.default.gray(HandlerCtor.name)}`);
878
521
  const handler = new HandlerCtor(args, this.core);
879
522
  if (handler.hasChecks()) {
880
523
  await handler.runChecks();
@@ -985,11 +628,34 @@ function storeMetadata(symbol, routes, constructor) {
985
628
  Reflect.defineMetadata(InteractionMetadataKey, true, constructor);
986
629
  }
987
630
  __name(storeMetadata, "storeMetadata");
631
+
632
+ // src/bot/errors/Database.ts
633
+ var DatabaseError = class extends CustomError {
634
+ static {
635
+ __name(this, "DatabaseError");
636
+ }
637
+ uuid;
638
+ _emit = true;
639
+ /**
640
+ * Creates a new DatabaseError.
641
+ *
642
+ * @param message - The error message describing what went wrong
643
+ * @param uuid - A unique identifier for this specific error instance
644
+ */
645
+ constructor(message, uuid) {
646
+ super(message), this.uuid = uuid;
647
+ this.name = "DatabaseError";
648
+ this.response.setTitle("Database Error").setDescription(`An error occurred while interacting with the database.
649
+ ### UUID: \`${this.uuid}\``);
650
+ }
651
+ };
652
+
653
+ // src/bot/utilities/ErrorHandlingUtils.ts
988
654
  var ErrorHandlingUtils = class {
989
655
  static {
990
656
  __name(this, "ErrorHandlingUtils");
991
657
  }
992
- static logger = new Logger("Errors");
658
+ static logger = new services.Logger("Errors");
993
659
  /**
994
660
  * Processes an error and extracts the standardized response, if available.
995
661
  *
@@ -1130,7 +796,7 @@ var InteractionController = class {
1130
796
  __name(this, "InteractionController");
1131
797
  }
1132
798
  core;
1133
- logger = new Logger("Interactions");
799
+ logger = new services.Logger("Interactions");
1134
800
  isInitialized = false;
1135
801
  slashMap = /* @__PURE__ */ new Map();
1136
802
  buttonMap = /* @__PURE__ */ new Map();
@@ -1155,31 +821,31 @@ var InteractionController = class {
1155
821
  if (this.isInitialized) return;
1156
822
  this.isInitialized = true;
1157
823
  const handlersDir = this.core.config.bot.interactions.path;
1158
- this.logger.info(chalk6__default.default.bold(handlersDir));
824
+ this.logger.info(chalk2__default.default.bold(handlersDir));
1159
825
  await this.loadHandlers(handlersDir);
1160
826
  this.attachToClient();
1161
- this.logger.info(`${chalk6__default.default.bold.green("Loaded interaction handlers:")}`);
1162
- this.logger.info(`\u2192 ${chalk6__default.default.magenta.bold(this.slashMap.size)} slash commands`);
1163
- this.logger.info(`\u2192 ${chalk6__default.default.magenta.bold(this.buttonMap.size)} buttons`);
1164
- this.logger.info(`\u2192 ${chalk6__default.default.magenta.bold(this.modalMap.size)} modals`);
1165
- this.logger.info(`\u2192 ${chalk6__default.default.magenta.bold(this.stringSelectMap.size)} string selects`);
1166
- this.logger.info(`\u2192 ${chalk6__default.default.magenta.bold(this.userSelectMap.size)} user selects`);
1167
- this.logger.info(`\u2192 ${chalk6__default.default.magenta.bold(this.roleSelectMap.size)} role selects`);
1168
- this.logger.info(`\u2192 ${chalk6__default.default.magenta.bold(this.channelSelectMap.size)} channel selects`);
1169
- this.logger.info(`\u2192 ${chalk6__default.default.magenta.bold(this.mentionableSelectMap.size)} mentionable selects`);
1170
- this.logger.info(`\u2192 ${chalk6__default.default.magenta.bold(this.messageContextMenuMap.size)} message context menus`);
1171
- this.logger.info(`\u2192 ${chalk6__default.default.magenta.bold(this.userContextMenuMap.size)} user context menus`);
1172
- this.logger.info(`\u2192 ${chalk6__default.default.magenta.bold(this.autocompleteMap.size)} autocomplete`);
827
+ this.logger.info(`${chalk2__default.default.bold.green("Loaded interaction handlers:")}`);
828
+ this.logger.info(`\u2192 ${chalk2__default.default.magenta.bold(this.slashMap.size)} slash commands`);
829
+ this.logger.info(`\u2192 ${chalk2__default.default.magenta.bold(this.buttonMap.size)} buttons`);
830
+ this.logger.info(`\u2192 ${chalk2__default.default.magenta.bold(this.modalMap.size)} modals`);
831
+ this.logger.info(`\u2192 ${chalk2__default.default.magenta.bold(this.stringSelectMap.size)} string selects`);
832
+ this.logger.info(`\u2192 ${chalk2__default.default.magenta.bold(this.userSelectMap.size)} user selects`);
833
+ this.logger.info(`\u2192 ${chalk2__default.default.magenta.bold(this.roleSelectMap.size)} role selects`);
834
+ this.logger.info(`\u2192 ${chalk2__default.default.magenta.bold(this.channelSelectMap.size)} channel selects`);
835
+ this.logger.info(`\u2192 ${chalk2__default.default.magenta.bold(this.mentionableSelectMap.size)} mentionable selects`);
836
+ this.logger.info(`\u2192 ${chalk2__default.default.magenta.bold(this.messageContextMenuMap.size)} message context menus`);
837
+ this.logger.info(`\u2192 ${chalk2__default.default.magenta.bold(this.userContextMenuMap.size)} user context menus`);
838
+ this.logger.info(`\u2192 ${chalk2__default.default.magenta.bold(this.autocompleteMap.size)} autocomplete`);
1173
839
  }
1174
840
  async loadHandlers(dir) {
1175
- await traverseDirectory(dir, (_fullPath, relativePath, imported) => {
841
+ await utils.traverseDirectory(dir, (_fullPath, relativePath, imported) => {
1176
842
  for (const val of Object.values(imported)) {
1177
843
  if (this.isHandlerClass(val)) {
1178
844
  this.registerHandler(val);
1179
- this.logger.info(`${chalk6__default.default.italic("Registered")} ${chalk6__default.default.bold.yellow(val.name)} from ${chalk6__default.default.gray(relativePath)}`);
845
+ this.logger.info(`${chalk2__default.default.italic("Registered")} ${chalk2__default.default.bold.yellow(val.name)} from ${chalk2__default.default.gray(relativePath)}`);
1180
846
  }
1181
847
  }
1182
- });
848
+ }, this.logger);
1183
849
  }
1184
850
  isHandlerClass(obj) {
1185
851
  if (typeof obj !== "function") return false;
@@ -1245,7 +911,7 @@ var InteractionController = class {
1245
911
  attachToClient() {
1246
912
  this.core.bot.client.on(discord_js.Events.InteractionCreate, (interaction) => {
1247
913
  this.handleInteraction(interaction).catch((err) => {
1248
- this.logger.error(`[${chalk6__default.default.bold.red("UNHANDLED ERROR AT ROOT")}] ${err.name}`, err.stack);
914
+ this.logger.error(`[${chalk2__default.default.bold.red("UNHANDLED ERROR AT ROOT")}] ${err.name}`, err.stack);
1249
915
  });
1250
916
  });
1251
917
  }
@@ -1274,10 +940,10 @@ var InteractionController = class {
1274
940
  }
1275
941
  let HandlerCtor = getHandler(key);
1276
942
  if (!HandlerCtor) {
1277
- this.logger.warn(`No handler found for key ${chalk6__default.default.bold.cyan(key)}. Falling back to UnhandledEvent.`);
943
+ this.logger.warn(`No handler found for key ${chalk2__default.default.bold.cyan(key)}. Falling back to UnhandledEvent.`);
1278
944
  HandlerCtor = UnhandledEvent;
1279
945
  }
1280
- this.logger.debug(`Processing ${chalk6__default.default.bold.green(key)} with ${chalk6__default.default.gray(HandlerCtor.name)}`);
946
+ this.logger.debug(`Processing ${chalk2__default.default.bold.green(key)} with ${chalk2__default.default.gray(HandlerCtor.name)}`);
1281
947
  const handler = new HandlerCtor(interaction, this.core, args);
1282
948
  if (handler.hasChecks()) await handler.runChecks();
1283
949
  if (handler.shouldBreak()) return;
@@ -1381,13 +1047,13 @@ var EmojiInjector = class {
1381
1047
  __name(this, "EmojiInjector");
1382
1048
  }
1383
1049
  core;
1384
- logger = new Logger("Emojis");
1050
+ logger = new services.Logger("Emojis");
1385
1051
  constructor(core) {
1386
1052
  this.core = core;
1387
1053
  }
1388
1054
  async init() {
1389
1055
  if (!this.core.config.bot.emojis || Object.keys(this.core.config.bot.emojis).length === 0) {
1390
- this.logger.info(`${chalk6__default.default.bold.green("Loaded")}: ${chalk6__default.default.magenta.bold("0")} emojis`);
1056
+ this.logger.info(`${chalk2__default.default.bold.green("Loaded")}: ${chalk2__default.default.magenta.bold("0")} emojis`);
1391
1057
  return;
1392
1058
  }
1393
1059
  const configEmojis = this.core.config.bot.emojis;
@@ -1398,337 +1064,31 @@ var EmojiInjector = class {
1398
1064
  if (emoji) {
1399
1065
  configEmojis[key] = `<${emoji.identifier}>`;
1400
1066
  foundCount++;
1067
+ this.logger.debug(`${chalk2__default.default.bold.green("Found")}: ${chalk2__default.default.magenta.bold(emojiName)} (${emoji.id})`);
1401
1068
  }
1402
1069
  });
1403
- this.logger.info(`${chalk6__default.default.bold.green("Loaded")}: ${chalk6__default.default.magenta.bold(foundCount)} emojis`);
1404
- }
1405
- };
1406
- var Plugin = class {
1407
- static {
1408
- __name(this, "Plugin");
1409
- }
1410
- pluggable;
1411
- constructor(pluggable) {
1412
- this.pluggable = pluggable;
1413
- }
1414
- };
1415
- var Pluggable = class _Pluggable {
1416
- static {
1417
- __name(this, "Pluggable");
1418
- }
1419
- isInitialized = false;
1420
- shutdown;
1421
- startup;
1422
- static PLUGIN_INIT_TIMEOUT_MS = 15e3;
1423
- constructor(shutdown, startup) {
1424
- this.shutdown = shutdown;
1425
- this.startup = startup;
1426
- }
1427
- async init() {
1428
- if (this.isInitialized) return this;
1429
- await this.startup.run();
1430
- this.isInitialized = true;
1431
- return this;
1432
- }
1433
- /**
1434
- * Attaches a plugin to this instance
1435
- *
1436
- * Plugins provide external functionality and are initialized during the specified startup phase.
1437
- * The plugin instance becomes available as a property in `core` wherever it's available.
1438
- *
1439
- * Make sure to augment the {@link Core} interface with the plugin type to ensure TypeScript recognizes it and provides intellisense.
1440
- *
1441
- * @typeParam Key - The property name for accessing the plugin
1442
- * @typeParam Ctor - The plugin constructor type
1443
- * @param key - Property name to access the plugin instance
1444
- * @param Plugin - Plugin constructor class
1445
- * @param startupPhase - When during startup to initialize this plugin ({@link StartupPhase})
1446
- * @param args - Additional arguments to pass to the plugin constructor
1447
- * @returns This instance with the plugin attached as a typed property
1448
- * @throws An {@link Error} When called after initialization or if key already exists
1449
- * @example
1450
- * ```typescript
1451
- * seedcord.attach('db', Mongo, StartupPhase.Configuration, { uri: 'mongodb://...', dbName: 'seedcord' })
1452
- * ```
1453
- */
1454
- attach(key, Plugin2, startupPhase, ...args) {
1455
- if (this.isInitialized) throw new Error("Cannot attach a plugin after initialization.");
1456
- if (this[key]) throw new Error(`Plugin with key "${key}" already exists.`);
1457
- const instance = new Plugin2(this, ...args);
1458
- const entry = {
1459
- [key]: instance
1460
- };
1461
- this.startup.addTask(startupPhase, `Plugin:${key}`, async () => {
1462
- instance.logger.info(chalk6__default.default.bold("Initializing"));
1463
- await instance.init();
1464
- instance.logger.info(chalk6__default.default.bold("Initialized"));
1465
- }, _Pluggable.PLUGIN_INIT_TIMEOUT_MS);
1466
- return Object.assign(this, entry);
1467
- }
1468
- };
1469
- var CoordinatedLifecycle = class {
1470
- static {
1471
- __name(this, "CoordinatedLifecycle");
1472
- }
1473
- phaseOrder;
1474
- phaseEnum;
1475
- logger;
1476
- events = new events.EventEmitter();
1477
- tasksMap = /* @__PURE__ */ new Map();
1478
- constructor(loggerName, phaseOrder, phaseEnum) {
1479
- this.phaseOrder = phaseOrder;
1480
- this.phaseEnum = phaseEnum;
1481
- this.logger = new Logger(loggerName);
1482
- this.phaseOrder.forEach((phase) => this.tasksMap.set(phase, []));
1483
- }
1484
- /**
1485
- * Adds a lifecycle task to a specific phase.
1486
- *
1487
- * Tasks are executed in phase order during lifecycle operations.
1488
- * Each task has a timeout to prevent hanging operations.
1489
- *
1490
- * @param phase - The lifecycle phase to add the task to
1491
- * @param taskName - Unique name for the task (used for logging and removal)
1492
- * @param task - Async function to execute during the phase
1493
- * @param timeoutMs - Maximum time allowed for task execution in milliseconds
1494
- * @example
1495
- * ```typescript
1496
- * lifecycle.addTask(StartupPhase.Services, 'start-database', async () => {
1497
- * await database.connect();
1498
- * }, 10000);
1499
- * ```
1500
- */
1501
- addTask(phase, taskName, task, timeoutMs) {
1502
- if (!this.canAddTask()) return;
1503
- const tasks = this.tasksMap.get(phase);
1504
- if (!tasks) throw new Error(`Unknown phase: ${phase}`);
1505
- tasks.push({
1506
- name: taskName,
1507
- task,
1508
- timeout: timeoutMs
1509
- });
1510
- this.logger.debug(`${chalk6__default.default.italic("Added")} ${this.getTaskType()} task ${chalk6__default.default.bold.cyan(taskName)} to phase ${chalk6__default.default.bold.magenta(this.phaseEnum[phase])}`);
1511
- }
1512
- /**
1513
- * Removes a lifecycle task from a specific phase.
1514
- *
1515
- * @param phase - The lifecycle phase to remove the task from
1516
- * @param taskName - Name of the task to remove
1517
- * @returns True if the task was found and removed, false otherwise
1518
- */
1519
- removeTask(phase, taskName) {
1520
- if (!this.canRemoveTask()) return false;
1521
- const tasks = this.tasksMap.get(phase);
1522
- if (!tasks) return false;
1523
- const initialLength = tasks.length;
1524
- const filteredTasks = tasks.filter((task) => task.name !== taskName);
1525
- this.tasksMap.set(phase, filteredTasks);
1526
- const removed = initialLength !== filteredTasks.length;
1527
- if (removed) {
1528
- this.logger.debug(`${chalk6__default.default.italic("Removed")} ${this.getTaskType()} task ${chalk6__default.default.bold.cyan(taskName)} from phase ${chalk6__default.default.bold.magenta(this.phaseEnum[phase])}`);
1529
- }
1530
- return removed;
1531
- }
1532
- /**
1533
- * Run all tasks in a specific phase
1534
- */
1535
- async runPhase(phase) {
1536
- const tasks = this.tasksMap.get(phase) ?? [];
1537
- if (tasks.length === 0) {
1538
- this.logger.warn(`No tasks to run in phase ${chalk6__default.default.bold.magenta(this.phaseEnum[phase])}`);
1539
- return;
1540
- }
1541
- this.logger.info(`${chalk6__default.default.bold.yellow("Running")} ${this.getTaskType()} phase ${chalk6__default.default.bold.magenta(this.phaseEnum[phase])} with ${chalk6__default.default.bold.cyan(tasks.length)} tasks`);
1542
- this.emit(`phase:${phase}:start`);
1543
- const results = await this.executeTasksInPhase(phase, tasks);
1544
- const failures = results.filter((r) => r.status === "rejected").length;
1545
- if (failures > 0) {
1546
- const errorMessage = `Phase ${chalk6__default.default.bold.magenta(this.phaseEnum[phase])} completed with ${chalk6__default.default.bold.red(failures)} failed tasks`;
1547
- throw new Error(errorMessage);
1548
- } else {
1549
- this.logger.info(`Phase ${chalk6__default.default.bold.magenta(this.phaseEnum[phase])} ${chalk6__default.default.bold.green("completed successfully")}`);
1550
- }
1551
- this.emit(`phase:${phase}:complete`);
1552
- }
1553
- /**
1554
- * Run a single task with timeout
1555
- */
1556
- async runTaskWithTimeout(phase, task) {
1557
- this.logger.info(`${chalk6__default.default.italic("Starting")} task ${chalk6__default.default.bold.cyan(task.name)} in phase ${chalk6__default.default.bold.magenta(this.phaseEnum[phase])}`);
1558
- try {
1559
- await Promise.race([
1560
- task.task(),
1561
- new Promise((_, reject) => {
1562
- setTimeout(() => {
1563
- reject(new Error(`Task '${task.name}' timed out after ${task.timeout}ms`));
1564
- }, task.timeout);
1565
- })
1566
- ]);
1567
- this.logger.info(`${chalk6__default.default.italic("Completed")} task ${chalk6__default.default.bold.cyan(task.name)} in phase ${chalk6__default.default.bold.magenta(this.phaseEnum[phase])}`);
1568
- } catch (error) {
1569
- this.logger.error(`${chalk6__default.default.italic("Failed")} task ${chalk6__default.default.bold.cyan(task.name)} in phase ${chalk6__default.default.bold.magenta(this.phaseEnum[phase])}:`, error);
1570
- throw error;
1571
- }
1572
- }
1573
- /**
1574
- * Subscribe to lifecycle events
1575
- */
1576
- on(event, listener) {
1577
- this.events.on(event, listener);
1578
- }
1579
- /**
1580
- * Unsubscribe from lifecycle events
1581
- */
1582
- off(event, listener) {
1583
- this.events.off(event, listener);
1584
- }
1585
- emit(event, ...args) {
1586
- return this.events.emit(event, ...args);
1587
- }
1588
- };
1589
-
1590
- // src/services/Lifecycle/CoordinatedShutdown.ts
1591
- var ShutdownPhase = /* @__PURE__ */ (function(ShutdownPhase2) {
1592
- ShutdownPhase2[ShutdownPhase2["StopAcceptingRequests"] = 1] = "StopAcceptingRequests";
1593
- ShutdownPhase2[ShutdownPhase2["StopServices"] = 2] = "StopServices";
1594
- ShutdownPhase2[ShutdownPhase2["ExternalResources"] = 3] = "ExternalResources";
1595
- ShutdownPhase2[ShutdownPhase2["DiscordCleanup"] = 4] = "DiscordCleanup";
1596
- ShutdownPhase2[ShutdownPhase2["FinalCleanup"] = 5] = "FinalCleanup";
1597
- return ShutdownPhase2;
1598
- })({});
1599
- var PHASE_ORDER = [
1600
- 1,
1601
- 2,
1602
- 3,
1603
- 4,
1604
- 5
1605
- ];
1606
- var LOG_FLUSH_DELAY_MS = 500;
1607
- var CoordinatedShutdown = class extends CoordinatedLifecycle {
1608
- static {
1609
- __name(this, "CoordinatedShutdown");
1610
- }
1611
- isShuttingDown = false;
1612
- exitCode = 0;
1613
- constructor() {
1614
- super("CoordinatedShutdown", PHASE_ORDER, ShutdownPhase);
1615
- this.registerSignalHandlers();
1616
- }
1617
- canAddTask() {
1618
- return Globals.shutdownIsEnabled;
1619
- }
1620
- canRemoveTask() {
1621
- return true;
1622
- }
1623
- getTaskType() {
1624
- return "shutdown";
1625
- }
1626
- async executeTasksInPhase(phase, tasks) {
1627
- const results = [];
1628
- for (const task of tasks) {
1629
- results.push(await Promise.resolve().then(() => this.runTaskWithTimeout(phase, task)).then(() => ({
1630
- status: "fulfilled",
1631
- value: void 0
1632
- }), (reason) => ({
1633
- status: "rejected",
1634
- reason
1635
- })));
1636
- }
1637
- return results;
1638
- }
1639
- registerSignalHandlers() {
1640
- if (!Globals.shutdownIsEnabled) return;
1641
- process.on("SIGTERM", () => {
1642
- this.logger.info(`Received ${chalk6__default.default.yellow.bold("SIGTERM")} signal`);
1643
- void this.run(0);
1644
- });
1645
- process.on("SIGINT", () => {
1646
- this.logger.info(`Received ${chalk6__default.default.yellow.bold("SIGINT")} signal`);
1647
- void this.run(0);
1648
- });
1649
- }
1650
- /**
1651
- * Adds a task to a specific shutdown phase with timeout.
1652
- *
1653
- * @param phase - The shutdown phase from {@link ShutdownPhase}
1654
- * @param taskName - Unique identifier for the task
1655
- * @param task - Async function to execute
1656
- * @param timeoutMs - Task timeout in milliseconds (default: 5000)
1657
- */
1658
- addTask(phase, taskName, task, timeoutMs = 5e3) {
1659
- super.addTask(phase, taskName, task, timeoutMs);
1660
- }
1661
- /**
1662
- * Removes a task from a specific shutdown phase.
1663
- *
1664
- * @param phase - The shutdown phase to remove from
1665
- * @param taskName - Name of the task to remove
1666
- * @returns True if task was found and removed
1667
- */
1668
- removeTask(phase, taskName) {
1669
- return super.removeTask(phase, taskName);
1670
- }
1671
- /**
1672
- * Executes the coordinated shutdown sequence.
1673
- *
1674
- * Runs all registered tasks across shutdown phases in reverse order.
1675
- * Tasks within each phase are executed in parallel for faster shutdown.
1676
- * Process exits with the specified code when complete.
1677
- *
1678
- * @param exitCode - Process exit code (default: 0)
1679
- * @returns Promise that resolves when shutdown is complete
1680
- * @example
1681
- * ```typescript
1682
- * shutdown.addTask(ShutdownPhase.Services, 'database', () => db.disconnect(), 5000);
1683
- * await shutdown.run(0); // Graceful shutdown
1684
- * ```
1685
- */
1686
- async run(exitCode = 0) {
1687
- if (this.isShuttingDown) {
1688
- this.logger.warn("Shutdown sequence already in progress");
1689
- return;
1690
- }
1691
- this.isShuttingDown = true;
1692
- this.exitCode = exitCode;
1693
- this.logger.info(`${chalk6__default.default.bold.yellow("Starting")} coordinated shutdown with exit code ${chalk6__default.default.bold.cyan(exitCode)}`);
1694
- this.emit("shutdown:start");
1695
- try {
1696
- for (const phase of PHASE_ORDER) {
1697
- await this.runPhase(phase);
1698
- }
1699
- this.logger.info(`${chalk6__default.default.bold.green("Coordinated shutdown completed")} successfully`);
1700
- this.emit("shutdown:complete");
1701
- } catch (error) {
1702
- this.logger.error(`${chalk6__default.default.bold.red("Coordinated shutdown failed")}`);
1703
- this.emit("shutdown:error", error);
1704
- } finally {
1705
- this.logger.info(`${chalk6__default.default.bold.red("Exiting")} process with code ${chalk6__default.default.bold.cyan(this.exitCode)}`);
1706
- setTimeout(() => {
1707
- process.exit(this.exitCode);
1708
- }, LOG_FLUSH_DELAY_MS);
1709
- }
1710
- }
1711
- /**
1712
- * Subscribe to shutdown events
1713
- */
1714
- on(event, listener) {
1715
- super.on(event, listener);
1716
- }
1717
- /**
1718
- * Unsubscribe from shutdown events
1719
- */
1720
- off(event, listener) {
1721
- super.off(event, listener);
1070
+ this.logger.info(`${chalk2__default.default.bold.green("Loaded")}: ${chalk2__default.default.magenta.bold(foundCount)} emojis`);
1722
1071
  }
1723
1072
  };
1724
1073
 
1725
1074
  // src/bot/Bot.ts
1075
+ function _ts_decorate3(decorators, target, key, desc) {
1076
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1077
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1078
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1079
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1080
+ }
1081
+ __name(_ts_decorate3, "_ts_decorate");
1082
+ function _ts_metadata3(k, v) {
1083
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1084
+ }
1085
+ __name(_ts_metadata3, "_ts_metadata");
1726
1086
  var Bot = class extends Plugin {
1727
1087
  static {
1728
1088
  __name(this, "Bot");
1729
1089
  }
1730
1090
  core;
1731
- logger = new Logger("Bot");
1091
+ logger = new services.Logger("Bot");
1732
1092
  isInitialized = false;
1733
1093
  _client;
1734
1094
  interactions;
@@ -1746,7 +1106,7 @@ var Bot = class extends Plugin {
1746
1106
  this.events = new EventController(core);
1747
1107
  this.commands = new CommandRegistry(this.core);
1748
1108
  this.emojiInjector = new EmojiInjector(this.core);
1749
- this.core.shutdown.addTask(ShutdownPhase.DiscordCleanup, "stop-bot", async () => await this.stop());
1109
+ this.core.shutdown.addTask(services.ShutdownPhase.DiscordCleanup, "stop-bot", async () => await this.stop());
1750
1110
  }
1751
1111
  /**
1752
1112
  * Initializes Discord client and all controllers
@@ -1776,8 +1136,8 @@ var Bot = class extends Plugin {
1776
1136
  * Logs the bot into Discord using the configured token
1777
1137
  */
1778
1138
  async login() {
1779
- await this._client.login(Globals.botToken);
1780
- this.logger.info(`Logged in as ${chalk6__default.default.bold.magenta(this._client.user?.username)}!`);
1139
+ await this._client.login(this.botToken);
1140
+ this.logger.info(`Logged in as ${chalk2__default.default.bold.magenta(this._client.user?.username)}!`);
1781
1141
  return this;
1782
1142
  }
1783
1143
  /**
@@ -1785,12 +1145,21 @@ var Bot = class extends Plugin {
1785
1145
  */
1786
1146
  async logout() {
1787
1147
  await this._client.destroy();
1788
- this.logger.info(chalk6__default.default.bold.red("Logged out of Discord!"));
1148
+ this.logger.info(chalk2__default.default.bold.red("Logged out of Discord!"));
1789
1149
  }
1790
1150
  get client() {
1791
1151
  return this._client;
1792
1152
  }
1793
1153
  };
1154
+ _ts_decorate3([
1155
+ envapt.Envapt("DISCORD_BOT_TOKEN", {
1156
+ converter(raw, _fallback) {
1157
+ if (typeof raw !== "string") throw new Error("Missing DISCORD_BOT_TOKEN");
1158
+ return raw;
1159
+ }
1160
+ }),
1161
+ _ts_metadata3("design:type", String)
1162
+ ], Bot.prototype, "botToken", void 0);
1794
1163
 
1795
1164
  // src/effects/decorators/RegisterEffect.ts
1796
1165
  var EffectMetadataKey = Symbol("effect:metadata");
@@ -1833,19 +1202,23 @@ var WebhookLog = class extends EffectsHandler {
1833
1202
  };
1834
1203
 
1835
1204
  // src/effects/default/UnknownException.ts
1836
- function _ts_decorate3(decorators, target, key, desc) {
1205
+ function _ts_decorate4(decorators, target, key, desc) {
1837
1206
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1838
1207
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1839
1208
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1840
1209
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1841
1210
  }
1842
- __name(_ts_decorate3, "_ts_decorate");
1843
- var UnknownException = class extends WebhookLog {
1211
+ __name(_ts_decorate4, "_ts_decorate");
1212
+ function _ts_metadata4(k, v) {
1213
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1214
+ }
1215
+ __name(_ts_metadata4, "_ts_metadata");
1216
+ var UnknownException = class _UnknownException extends WebhookLog {
1844
1217
  static {
1845
1218
  __name(this, "UnknownException");
1846
1219
  }
1847
1220
  webhook = new discord_js.WebhookClient({
1848
- url: Globals.unknownExceptionWebhookUrl
1221
+ url: _UnknownException.unknownExceptionWebhookUrl
1849
1222
  });
1850
1223
  async execute() {
1851
1224
  await this.webhook.send({
@@ -1857,7 +1230,16 @@ var UnknownException = class extends WebhookLog {
1857
1230
  });
1858
1231
  }
1859
1232
  };
1860
- UnknownException = _ts_decorate3([
1233
+ _ts_decorate4([
1234
+ envapt.Envapt("UNKNOWN_EXCEPTION_WEBHOOK_URL", {
1235
+ converter(raw, _fallback) {
1236
+ if (!raw) throw new Error("Missing UNKNOWN_EXCEPTION_WEBHOOK_URL");
1237
+ return raw;
1238
+ }
1239
+ }),
1240
+ _ts_metadata4("design:type", String)
1241
+ ], UnknownException, "unknownExceptionWebhookUrl", void 0);
1242
+ UnknownException = _ts_decorate4([
1861
1243
  RegisterEffect("unknownException")
1862
1244
  ], UnknownException);
1863
1245
  var UnhandledErrorEmbed = class UnhandledErrorEmbed2 extends BuilderComponent {
@@ -1943,7 +1325,7 @@ var EffectsRegistry = class extends Plugin {
1943
1325
  __name(this, "EffectsRegistry");
1944
1326
  }
1945
1327
  core;
1946
- logger = new Logger("Effects");
1328
+ logger = new services.Logger("Effects");
1947
1329
  isInitialized = false;
1948
1330
  effectsMap = /* @__PURE__ */ new Map();
1949
1331
  emitter = new EffectsEmitter();
@@ -1954,26 +1336,26 @@ var EffectsRegistry = class extends Plugin {
1954
1336
  if (this.isInitialized) return;
1955
1337
  this.isInitialized = true;
1956
1338
  const effectsDir = this.core.config.effects.path;
1957
- this.logger.info(chalk6__default.default.bold(effectsDir));
1339
+ this.logger.info(chalk2__default.default.bold(effectsDir));
1958
1340
  this.registerEffect("unknownException", UnknownException);
1959
1341
  await this.loadEffects(effectsDir);
1960
1342
  this.attachEffects();
1961
1343
  const totalEffects = Array.from(this.effectsMap.values()).reduce((acc, handlers) => acc + handlers.length, 0);
1962
- this.logger.info(`${chalk6__default.default.bold.green("Loaded")}: ${chalk6__default.default.bold.magenta(totalEffects)} side effects`);
1344
+ this.logger.info(`${chalk2__default.default.bold.green("Loaded")}: ${chalk2__default.default.bold.magenta(totalEffects)} side effects`);
1963
1345
  }
1964
1346
  async loadEffects(dir) {
1965
- await traverseDirectory(dir, (_fullPath, relativePath, imported) => {
1347
+ await utils.traverseDirectory(dir, (_fullPath, relativePath, imported) => {
1966
1348
  for (const exportName of Object.keys(imported)) {
1967
1349
  const val = imported[exportName];
1968
1350
  if (this.isEffectHandler(val)) {
1969
1351
  const effectName = Reflect.getMetadata(EffectMetadataKey, val);
1970
1352
  if (effectName) {
1971
1353
  this.registerEffect(effectName, val);
1972
- this.logger.info(`${chalk6__default.default.italic("Registered")} ${chalk6__default.default.bold.yellow(val.name)} from ${chalk6__default.default.gray(relativePath)}`);
1354
+ this.logger.info(`${chalk2__default.default.italic("Registered")} ${chalk2__default.default.bold.yellow(val.name)} from ${chalk2__default.default.gray(relativePath)}`);
1973
1355
  }
1974
1356
  }
1975
1357
  }
1976
- });
1358
+ }, this.logger);
1977
1359
  }
1978
1360
  registerEffect(effectName, handler) {
1979
1361
  let handlers = this.effectsMap.get(effectName);
@@ -2005,202 +1387,6 @@ var EffectsRegistry = class extends Plugin {
2005
1387
  return this.emitter.emit(event, data);
2006
1388
  }
2007
1389
  };
2008
- var HTTP_OK = 200;
2009
- var HTTP_NOT_FOUND = 404;
2010
- var HealthCheck = class extends Plugin {
2011
- static {
2012
- __name(this, "HealthCheck");
2013
- }
2014
- core;
2015
- logger = new Logger("HealthCheck");
2016
- port = Globals.healthCheckPort;
2017
- path = Globals.healthCheckPath;
2018
- server;
2019
- constructor(core) {
2020
- super(core), this.core = core;
2021
- this.core.shutdown.addTask(ShutdownPhase.StopServices, "stop-healthcheck-server", async () => await this.stop());
2022
- }
2023
- /**
2024
- * Starts the health check server.
2025
- * @returns Promise that resolves when the server is listening
2026
- */
2027
- async init() {
2028
- return new Promise((resolve, reject) => {
2029
- this.server = http.createServer((req, res) => {
2030
- if (req.method === "GET" && req.url === this.path) {
2031
- res.writeHead(HTTP_OK, {
2032
- "Content-Type": "application/json"
2033
- });
2034
- res.end(JSON.stringify({
2035
- status: "ok",
2036
- timestamp: Date.now()
2037
- }));
2038
- } else {
2039
- res.writeHead(HTTP_NOT_FOUND, {
2040
- "Content-Type": "application/json"
2041
- });
2042
- res.end(JSON.stringify({
2043
- status: "not found"
2044
- }));
2045
- }
2046
- });
2047
- this.server.on("error", reject);
2048
- this.server.listen(this.port, () => {
2049
- this.logger.info(`${chalk6__default.default.green.bold("\u2713")} Health check server listening on ${chalk6__default.default.cyan(`http://localhost:${this.port}${this.path}`)}`);
2050
- resolve();
2051
- });
2052
- });
2053
- }
2054
- /**
2055
- * Stops the health check server.
2056
- *
2057
- * @returns Promise that resolves when the server is closed
2058
- */
2059
- stop() {
2060
- return new Promise((shutdownResolve) => {
2061
- this.server?.close(() => {
2062
- this.logger.info(chalk6__default.default.bold.red("Health check server stopped"));
2063
- shutdownResolve();
2064
- });
2065
- });
2066
- }
2067
- };
2068
- var StartupPhase = /* @__PURE__ */ (function(StartupPhase2) {
2069
- StartupPhase2[StartupPhase2["Validation"] = 1] = "Validation";
2070
- StartupPhase2[StartupPhase2["Discovery"] = 2] = "Discovery";
2071
- StartupPhase2[StartupPhase2["Registration"] = 3] = "Registration";
2072
- StartupPhase2[StartupPhase2["Configuration"] = 4] = "Configuration";
2073
- StartupPhase2[StartupPhase2["Instantiation"] = 5] = "Instantiation";
2074
- StartupPhase2[StartupPhase2["Activation"] = 6] = "Activation";
2075
- StartupPhase2[StartupPhase2["Ready"] = 7] = "Ready";
2076
- return StartupPhase2;
2077
- })({});
2078
- var PHASE_ORDER2 = [
2079
- 1,
2080
- 2,
2081
- 3,
2082
- 4,
2083
- 5,
2084
- 6,
2085
- 7
2086
- ];
2087
- var CoordinatedStartup = class extends CoordinatedLifecycle {
2088
- static {
2089
- __name(this, "CoordinatedStartup");
2090
- }
2091
- isStartingUp = false;
2092
- hasStarted = false;
2093
- constructor() {
2094
- super("CoordinatedStartup", PHASE_ORDER2, StartupPhase);
2095
- }
2096
- /**
2097
- * Adds a task to a specific startup phase with timeout.
2098
- *
2099
- * @param phase - The startup phase from {@link StartupPhase}
2100
- * @param taskName - Unique identifier for the task
2101
- * @param task - Async function to execute
2102
- * @param timeoutMs - Task timeout in milliseconds (default: 10000)
2103
- */
2104
- addTask(phase, taskName, task, timeoutMs = 1e4) {
2105
- super.addTask(phase, taskName, task, timeoutMs);
2106
- }
2107
- canAddTask() {
2108
- if (this.hasStarted) {
2109
- throw new Error("Cannot add tasks after startup sequence has already completed");
2110
- }
2111
- if (this.isStartingUp) {
2112
- throw new Error("Cannot add tasks while startup sequence is in progress");
2113
- }
2114
- return true;
2115
- }
2116
- canRemoveTask() {
2117
- if (this.isStartingUp) {
2118
- throw new Error("Cannot remove tasks while startup sequence is in progress");
2119
- }
2120
- return true;
2121
- }
2122
- getTaskType() {
2123
- return "startup";
2124
- }
2125
- async executeTasksInPhase(phase, tasks) {
2126
- const results = [];
2127
- for (const task of tasks) {
2128
- results.push(await Promise.resolve().then(() => this.runTaskWithTimeout(phase, task)).then(() => ({
2129
- status: "fulfilled",
2130
- value: void 0
2131
- }), (reason) => ({
2132
- status: "rejected",
2133
- reason
2134
- })));
2135
- }
2136
- return results;
2137
- }
2138
- /**
2139
- * Executes the coordinated startup sequence.
2140
- *
2141
- * Runs all registered tasks across startup phases in the correct order.
2142
- * Each phase completes before the next phase begins. Tasks within a phase
2143
- * are executed sequentially to maintain predictable initialization.
2144
- *
2145
- * @returns Promise that resolves when startup is complete
2146
- * @throws An {@link Error} If startup fails or is called multiple times
2147
- * @example
2148
- * ```typescript
2149
- * const startup = new CoordinatedStartup();
2150
- * startup.addTask(StartupPhase.Services, 'database', () => db.connect(), 10000);
2151
- * await startup.run();
2152
- * ```
2153
- */
2154
- async run() {
2155
- if (this.hasStarted) {
2156
- this.logger.warn("Startup sequence has already completed");
2157
- return;
2158
- }
2159
- if (this.isStartingUp) {
2160
- this.logger.warn("Startup sequence already in progress");
2161
- return;
2162
- }
2163
- this.isStartingUp = true;
2164
- this.logger.info(`${chalk6__default.default.bold.green("Starting")} coordinated startup sequence`);
2165
- this.emit("startup:start");
2166
- try {
2167
- for (const phase of PHASE_ORDER2) await this.runPhase(phase);
2168
- this.hasStarted = true;
2169
- this.logger.info(`${chalk6__default.default.bold.green("Coordinated startup completed")} successfully`);
2170
- this.emit("startup:complete");
2171
- } catch (error) {
2172
- this.logger.error(`${chalk6__default.default.bold.red("Coordinated startup failed")}`);
2173
- this.emit("startup:error", error);
2174
- throw error;
2175
- } finally {
2176
- this.isStartingUp = false;
2177
- }
2178
- }
2179
- /**
2180
- * Subscribe to startup events
2181
- */
2182
- on(event, listener) {
2183
- super.on(event, listener);
2184
- }
2185
- /**
2186
- * Unsubscribe from startup events
2187
- */
2188
- off(event, listener) {
2189
- super.off(event, listener);
2190
- }
2191
- /**
2192
- * Check if startup has completed
2193
- */
2194
- get isReady() {
2195
- return this.hasStarted;
2196
- }
2197
- /**
2198
- * Check if startup is currently running
2199
- */
2200
- get isRunning() {
2201
- return this.isStartingUp;
2202
- }
2203
- };
2204
1390
 
2205
1391
  // src/Seedcord.ts
2206
1392
  var Seedcord = class _Seedcord extends Pluggable {
@@ -2226,8 +1412,8 @@ var Seedcord = class _Seedcord extends Pluggable {
2226
1412
  * @throws An {@link Error} When attempting to create multiple instances (singleton)
2227
1413
  */
2228
1414
  constructor(config) {
2229
- const shutdown = new CoordinatedShutdown();
2230
- const startup = new CoordinatedStartup();
1415
+ const shutdown = new services.CoordinatedShutdown();
1416
+ const startup = new services.CoordinatedStartup();
2231
1417
  super(shutdown, startup), this.config = config;
2232
1418
  this.shutdown = shutdown;
2233
1419
  this.startup = startup;
@@ -2237,7 +1423,7 @@ var Seedcord = class _Seedcord extends Pluggable {
2237
1423
  _Seedcord.isInstantiated = true;
2238
1424
  this.effects = new EffectsRegistry(this);
2239
1425
  this.bot = new Bot(this);
2240
- this.healthCheck = new HealthCheck(this);
1426
+ this.healthCheck = new services.HealthCheck(this.shutdown);
2241
1427
  this.registerStartupTasks();
2242
1428
  }
2243
1429
  /**
@@ -2245,20 +1431,20 @@ var Seedcord = class _Seedcord extends Pluggable {
2245
1431
  * @internal
2246
1432
  */
2247
1433
  registerStartupTasks() {
2248
- this.startup.addTask(StartupPhase.Configuration, "Effect Initialization", async () => {
2249
- this.effects.logger.info(chalk6__default.default.bold("Initializing"));
1434
+ this.startup.addTask(services.StartupPhase.Configuration, "Effect Initialization", async () => {
1435
+ this.effects.logger.info(chalk2__default.default.bold("Initializing"));
2250
1436
  await this.effects.init();
2251
- this.effects.logger.info(chalk6__default.default.bold("Initialized"));
1437
+ this.effects.logger.info(chalk2__default.default.bold("Initialized"));
2252
1438
  });
2253
- this.startup.addTask(StartupPhase.Instantiation, "Bot Initialization", async () => {
2254
- this.bot.logger.info(chalk6__default.default.bold("Initializing"));
1439
+ this.startup.addTask(services.StartupPhase.Instantiation, "Bot Initialization", async () => {
1440
+ this.bot.logger.info(chalk2__default.default.bold("Initializing"));
2255
1441
  await this.bot.init();
2256
- this.bot.logger.info(chalk6__default.default.bold("Initialized"));
1442
+ this.bot.logger.info(chalk2__default.default.bold("Initialized"));
2257
1443
  });
2258
- this.startup.addTask(StartupPhase.Ready, "Health Check", async () => {
2259
- this.healthCheck.logger.info(chalk6__default.default.bold("Initializing"));
1444
+ this.startup.addTask(services.StartupPhase.Ready, "Health Check", async () => {
1445
+ this.healthCheck.logger.info(chalk2__default.default.bold("Initializing"));
2260
1446
  await this.healthCheck.init();
2261
- this.healthCheck.logger.info(chalk6__default.default.bold("Initialized"));
1447
+ this.healthCheck.logger.info(chalk2__default.default.bold("Initialized"));
2262
1448
  });
2263
1449
  }
2264
1450
  /**
@@ -2308,74 +1494,21 @@ function EventCatchable(log) {
2308
1494
  };
2309
1495
  }
2310
1496
  __name(EventCatchable, "EventCatchable");
2311
-
2312
- // src/services/CooldownManager.ts
2313
- var CooldownManager = class {
2314
- static {
2315
- __name(this, "CooldownManager");
2316
- }
2317
- window;
2318
- Err;
2319
- msg;
2320
- map = /* @__PURE__ */ new Map();
2321
- /**
2322
- * Creates a new CooldownManager instance.
2323
- *
2324
- * @param opts - Configuration options for the cooldown behavior
2325
- */
2326
- constructor(opts = {}) {
2327
- this.window = opts.cooldown ?? 1e3;
2328
- this.Err = opts.err ?? Error;
2329
- this.msg = opts.message ?? "Cooldown active";
2330
- }
2331
- /**
2332
- * Records usage timestamp for a key without any cooldown checks.
2333
- *
2334
- * @param key - The unique identifier for the cooldown entry
2335
- */
2336
- set(key) {
2337
- this.map.set(key, Date.now());
2338
- }
2339
- /**
2340
- * Verifies cooldown status for a key and updates timestamp if not active.
2341
- *
2342
- * If the cooldown is still active, throws the configured error.
2343
- * If not active, updates the timestamp and returns successfully.
2344
- *
2345
- * @param key - The unique identifier to check cooldown for
2346
- * @throws An {@link Err} When the cooldown is still active for the given key
2347
- */
2348
- check(key) {
2349
- const now = Date.now();
2350
- const last = this.map.get(key);
2351
- const remaining = this.window - (now - (last ?? 0));
2352
- if (Globals.isDevelopment && remaining > 0) {
2353
- Logger.Debug("CooldownManager", `${key} - ${remaining}ms remaining`);
2354
- }
2355
- if (last !== void 0 && remaining > 0) {
2356
- throw new this.Err(this.msg, remaining);
1497
+ function throwCustomError(error, message, CustomError2) {
1498
+ const uuid = crypto.randomUUID();
1499
+ services.Logger.Error("Throwing Custom Error", error.name);
1500
+ if (typeof CustomError2 === typeof DatabaseError) {
1501
+ const errorMessage = error instanceof Error ? error.message : message;
1502
+ throw new CustomError2(errorMessage, uuid);
1503
+ } else {
1504
+ if (error instanceof Error) {
1505
+ throw new CustomError2(`${message}: ${error.message ? error.message : error.toString()}`);
1506
+ } else {
1507
+ throw new CustomError2(message);
2357
1508
  }
2358
- this.map.set(key, now);
2359
- }
2360
- /**
2361
- * Checks if a key is currently cooling down without updating timestamp.
2362
- *
2363
- * @param key - The unique identifier to check
2364
- * @returns True if the key is still cooling down, false otherwise
2365
- */
2366
- isActive(key) {
2367
- const last = this.map.get(key);
2368
- return last !== void 0 && Date.now() - last < this.window;
2369
1509
  }
2370
- /**
2371
- * Removes a key from the cooldown map.
2372
- *
2373
- * @param key - The unique identifier to remove (useful for manual resets)
2374
- */
2375
- clear(key) {
2376
- this.map.delete(key);
2377
- }
2378
- };
1510
+ }
1511
+ __name(throwCustomError, "throwCustomError");
2379
1512
 
2380
1513
  exports.AutocompleteHandler = AutocompleteHandler;
2381
1514
  exports.AutocompleteRoute = AutocompleteRoute;
@@ -2387,9 +1520,6 @@ exports.Catchable = Catchable;
2387
1520
  exports.Checkable = Checkable;
2388
1521
  exports.CommandMetadataKey = CommandMetadataKey;
2389
1522
  exports.ContextMenuRoute = ContextMenuRoute;
2390
- exports.CooldownManager = CooldownManager;
2391
- exports.CoordinatedShutdown = CoordinatedShutdown;
2392
- exports.CoordinatedStartup = CoordinatedStartup;
2393
1523
  exports.CustomError = CustomError;
2394
1524
  exports.DatabaseError = DatabaseError;
2395
1525
  exports.EffectMetadataKey = EffectMetadataKey;
@@ -2399,13 +1529,10 @@ exports.EffectsRegistry = EffectsRegistry;
2399
1529
  exports.EventCatchable = EventCatchable;
2400
1530
  exports.EventHandler = EventHandler;
2401
1531
  exports.EventMetadataKey = EventMetadataKey;
2402
- exports.Globals = Globals;
2403
- exports.HealthCheck = HealthCheck;
2404
1532
  exports.InteractionHandler = InteractionHandler;
2405
1533
  exports.InteractionMetadataKey = InteractionMetadataKey;
2406
1534
  exports.InteractionMiddleware = InteractionMiddleware;
2407
1535
  exports.InteractionRoutes = InteractionRoutes;
2408
- exports.Logger = Logger;
2409
1536
  exports.ModalComponent = ModalComponent;
2410
1537
  exports.ModalRoute = ModalRoute;
2411
1538
  exports.Pluggable = Pluggable;
@@ -2417,22 +1544,20 @@ exports.RowComponent = RowComponent;
2417
1544
  exports.Seedcord = Seedcord;
2418
1545
  exports.SelectMenuRoute = SelectMenuRoute;
2419
1546
  exports.SelectMenuType = SelectMenuType;
2420
- exports.ShutdownPhase = ShutdownPhase;
2421
1547
  exports.SlashRoute = SlashRoute;
2422
- exports.StartupPhase = StartupPhase;
2423
1548
  exports.WebhookLog = WebhookLog;
2424
- exports.currentTime = currentTime;
2425
- exports.formatWord = formatWord;
2426
- exports.fyShuffle = fyShuffle;
2427
- exports.generateAsciiTable = generateAsciiTable;
2428
- exports.isTsOrJsFile = isTsOrJsFile;
2429
- exports.longestStringLength = longestStringLength;
2430
- exports.numberFixer = numberFixer;
2431
- exports.ordinal = ordinal;
2432
- exports.percentage = percentage;
2433
- exports.prettify = prettify;
2434
- exports.prettyDifference = prettyDifference;
2435
1549
  exports.throwCustomError = throwCustomError;
2436
- exports.traverseDirectory = traverseDirectory;
1550
+ Object.keys(services).forEach(function (k) {
1551
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
1552
+ enumerable: true,
1553
+ get: function () { return services[k]; }
1554
+ });
1555
+ });
1556
+ Object.keys(utils).forEach(function (k) {
1557
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
1558
+ enumerable: true,
1559
+ get: function () { return utils[k]; }
1560
+ });
1561
+ });
2437
1562
  //# sourceMappingURL=index.cjs.map
2438
1563
  //# sourceMappingURL=index.cjs.map