@seedcord/core 0.1.0 → 0.1.1-next.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.
Files changed (51) hide show
  1. package/dist/{HmrModuleHandler-CTBng7wV.cjs → HmrModuleHandler-CxGOo1LT.cjs} +43 -31
  2. package/dist/HmrModuleHandler-CxGOo1LT.cjs.map +1 -0
  3. package/dist/{HmrModuleHandler-3sNgKHdf.mjs → HmrModuleHandler-KxRP8lqJ.mjs} +43 -29
  4. package/dist/HmrModuleHandler-KxRP8lqJ.mjs.map +1 -0
  5. package/dist/{Plugin-BZit5HUI.d.mts → Plugin-BPz0obbN.d.mts} +19 -13
  6. package/dist/Plugin-CDAV7P9l.mjs.map +1 -1
  7. package/dist/{Plugin-BlkhHNRm.cjs → Plugin-DVNh1kvX.cjs} +3 -3
  8. package/dist/{Plugin-BlkhHNRm.cjs.map → Plugin-DVNh1kvX.cjs.map} +1 -1
  9. package/dist/{basic-1hebYVcN.d.mts → basic-CeSFvbaz.d.mts} +2 -3
  10. package/dist/{contextMenuLeaves-f2rbyo83.d.mts → contextMenuLeaves-CC3-qObq.d.mts} +1 -2
  11. package/dist/{cursor-j5bRcn2O.d.mts → cursor-Bk-W5MTq.d.mts} +16 -16
  12. package/dist/{cursor-BMkFAwO2.cjs → cursor-D2iP-CCS.cjs} +7 -4
  13. package/dist/cursor-D2iP-CCS.cjs.map +1 -0
  14. package/dist/{cursor-BvSH8tgw.mjs → cursor-Y6ct-N_8.mjs} +7 -4
  15. package/dist/{cursor-BvSH8tgw.mjs.map → cursor-Y6ct-N_8.mjs.map} +1 -1
  16. package/dist/{devChannel-CoCmAVDx.cjs → devChannel-Cdnmz6hd.cjs} +1 -2
  17. package/dist/{devChannel-CoCmAVDx.cjs.map → devChannel-Cdnmz6hd.cjs.map} +1 -1
  18. package/dist/hmr.index.cjs +1 -1
  19. package/dist/hmr.index.d.mts +2 -1
  20. package/dist/hmr.index.mjs +1 -1
  21. package/dist/{index-DafutfX8.d.mts → index-Dm0WKN37.d.mts} +4 -4
  22. package/dist/index.cjs +11 -7
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.mts +5 -5
  25. package/dist/index.mjs +10 -6
  26. package/dist/index.mjs.map +1 -1
  27. package/dist/internal.index.cjs +28 -29
  28. package/dist/internal.index.cjs.map +1 -1
  29. package/dist/internal.index.d.mts +9 -15
  30. package/dist/internal.index.mjs +28 -27
  31. package/dist/internal.index.mjs.map +1 -1
  32. package/dist/node-internal.index.cjs +63 -74
  33. package/dist/node-internal.index.cjs.map +1 -1
  34. package/dist/node-internal.index.d.mts +17 -24
  35. package/dist/node-internal.index.mjs +59 -70
  36. package/dist/node-internal.index.mjs.map +1 -1
  37. package/dist/{phases-DcuDHoQl.cjs → phases-8qiiLKjS.cjs} +1 -2
  38. package/dist/{phases-DcuDHoQl.cjs.map → phases-8qiiLKjS.cjs.map} +1 -1
  39. package/dist/plugin.index.cjs +1 -1
  40. package/dist/plugin.index.d.mts +1 -1
  41. package/dist/slashRouteLeaves-nfxOAM7Q.cjs.map +1 -1
  42. package/dist/{subscribers-CojcCgj1.cjs → subscribers-CDbep0RH.cjs} +36 -4
  43. package/dist/subscribers-CDbep0RH.cjs.map +1 -0
  44. package/dist/{subscribers-CmDKqC7y.mjs → subscribers-xO6DZ-70.mjs} +2 -2
  45. package/dist/{subscribers-CmDKqC7y.mjs.map → subscribers-xO6DZ-70.mjs.map} +1 -1
  46. package/package.json +18 -15
  47. package/dist/HmrModuleHandler-3sNgKHdf.mjs.map +0 -1
  48. package/dist/HmrModuleHandler-CTBng7wV.cjs.map +0 -1
  49. package/dist/cursor-BMkFAwO2.cjs.map +0 -1
  50. package/dist/rolldown-runtime-C_NdSu1c.cjs +0 -34
  51. package/dist/subscribers-CojcCgj1.cjs.map +0 -1
@@ -1,10 +1,10 @@
1
1
  import { g as contextMenuLeaves, i as BuilderComponent, m as SubscribeMetadataKey, s as CommandMetadataKey } from "./publishDefault-CldnxcT2.mjs";
2
2
  import { n as StartupPhase, t as ShutdownPhase } from "./phases-BauKJOTT.mjs";
3
- import { n as registrationFor, o as Subscriber } from "./subscribers-CmDKqC7y.mjs";
3
+ import { n as registrationFor, o as Subscriber } from "./subscribers-xO6DZ-70.mjs";
4
4
  import { t as getDevChannel } from "./devChannel-CQU7hq7Q.mjs";
5
5
  import { n as resolvedLifecycleSpecOf } from "./Plugin-CDAV7P9l.mjs";
6
6
  import { t as slashRouteLeaves } from "./slashRouteLeaves-BANDtPFm.mjs";
7
- import { t as HmrModuleHandler } from "./HmrModuleHandler-3sNgKHdf.mjs";
7
+ import { t as HmrModuleHandler } from "./HmrModuleHandler-KxRP8lqJ.mjs";
8
8
  import { SlashCommandBuilder } from "@discordjs/builders";
9
9
  import { FRAMEWORK_CHANNELS, Logger, paint } from "@seedcord/logger";
10
10
  import { Routes } from "discord-api-types/v10";
@@ -74,7 +74,7 @@ var CoordinatedLifecycle = class {
74
74
  task,
75
75
  timeout: timeoutMs
76
76
  });
77
- this.logger.debug(`${chalk.italic("Added")} ${this.getTaskType()} task ${chalk.bold.cyan(taskName)} to phase ${chalk.bold.magenta(this.phaseEnum[phase])}`);
77
+ this.logger.debug(`${chalk.italic("Added")} ${this.getTaskType()} task ${paint.sky.bold(taskName)} to phase ${paint.iris.bold(this.phaseEnum[phase])}`);
78
78
  }
79
79
  /**
80
80
  * Removes a lifecycle task from a specific phase.
@@ -91,30 +91,34 @@ var CoordinatedLifecycle = class {
91
91
  const filteredTasks = tasks.filter((task) => task.name !== taskName);
92
92
  this.tasksMap.set(phase, filteredTasks);
93
93
  const removed = initialLength !== filteredTasks.length;
94
- if (removed) this.logger.debug(`${chalk.italic("Removed")} ${this.getTaskType()} task ${chalk.bold.cyan(taskName)} from phase ${chalk.bold.magenta(this.phaseEnum[phase])}`);
94
+ if (removed) this.logger.debug(`${chalk.italic("Removed")} ${this.getTaskType()} task ${paint.sky.bold(taskName)} from phase ${paint.iris.bold(this.phaseEnum[phase])}`);
95
95
  return removed;
96
96
  }
97
97
  async runPhase(phase) {
98
98
  const tasks = this.tasksMap.get(phase) ?? [];
99
99
  if (tasks.length === 0) {
100
- this.logger.debug(`No tasks to run in phase ${chalk.bold.magenta(this.phaseEnum[phase])}`);
100
+ this.logger.trace(`No tasks to run in phase ${paint.iris.bold(this.phaseEnum[phase])}`);
101
101
  return;
102
102
  }
103
- this.logger.info(`${chalk.bold.yellow("Running")} ${this.getTaskType()} phase ${chalk.bold.magenta(this.phaseEnum[phase])} with ${chalk.bold.cyan(tasks.length)} tasks`);
103
+ this.logger.debug(`${paint.amber.bold("Running")} ${this.getTaskType()} phase ${paint.iris.bold(this.phaseEnum[phase])} with ${paint.sky.bold(String(tasks.length))} tasks`);
104
104
  const failures = (await this.executeTasksInPhase(phase, tasks)).filter((r) => r.status === "rejected").length;
105
105
  if (failures > 0) throw new SeedcordError(SeedcordErrorCode.LifecyclePhaseFailures, [this.phaseEnum[phase], failures]);
106
- this.logger.info(`Phase ${chalk.bold.magenta(this.phaseEnum[phase])} ${chalk.bold.green("completed successfully")}`);
106
+ this.logger.debug(`Phase ${paint.iris.bold(this.phaseEnum[phase])} ${paint.mint.bold("completed successfully")}`);
107
107
  }
108
108
  async runTaskWithTimeout(phase, task) {
109
- this.logger.info(`${chalk.italic("Starting")} task ${chalk.bold.cyan(task.name)} in phase ${chalk.bold.magenta(this.phaseEnum[phase])}`);
109
+ this.logger.trace(`${chalk.italic("Starting")} task ${paint.sky.bold(task.name)} in phase ${paint.iris.bold(this.phaseEnum[phase])}`);
110
110
  try {
111
111
  await withTimeout(task.name, task.task, task.timeout);
112
- this.logger.info(`${chalk.italic("Completed")} task ${chalk.bold.cyan(task.name)} in phase ${chalk.bold.magenta(this.phaseEnum[phase])}`);
112
+ this.logger.trace(`${chalk.italic("Completed")} task ${paint.sky.bold(task.name)} in phase ${paint.iris.bold(this.phaseEnum[phase])}`);
113
113
  } catch (error) {
114
- this.logger.error(`${chalk.italic("Failed")} task ${chalk.bold.cyan(task.name)} in phase ${chalk.bold.magenta(this.phaseEnum[phase])}:`, error);
114
+ if (this.isAborted()) return;
115
+ this.logger.error(`${chalk.italic("Failed")} task ${paint.sky.bold(task.name)} in phase ${paint.iris.bold(this.phaseEnum[phase])}:`, error);
115
116
  throw error;
116
117
  }
117
118
  }
119
+ isAborted() {
120
+ return false;
121
+ }
118
122
  };
119
123
 
120
124
  //#endregion
@@ -230,12 +234,12 @@ var CoordinatedShutdown = class extends CoordinatedLifecycle {
230
234
  } finally {
231
235
  this.hasShutdown = true;
232
236
  if (exitProcess) {
233
- this.logger.info(`${chalk.bold.red("Exiting")} process with code ${chalk.bold.cyan(this.exitCode)}`);
237
+ this.logger.debug(`${chalk.bold.red("Exiting")} process with code ${chalk.bold.cyan(this.exitCode)}`);
234
238
  setTimeout(() => {
235
239
  process.exit(this.exitCode);
236
240
  }, LOG_FLUSH_DELAY_MS);
237
241
  } else {
238
- this.logger.info(`${chalk.bold.yellow("Skipping")} process exit (dev mode)`);
242
+ this.logger.debug(`${chalk.bold.yellow("Skipping")} process exit (dev mode)`);
239
243
  this.isShuttingDown = false;
240
244
  }
241
245
  }
@@ -323,16 +327,8 @@ var CoordinatedStartup = class extends CoordinatedLifecycle {
323
327
  this.isStartingUp = false;
324
328
  }
325
329
  }
326
- async runTaskWithTimeout(phase, task) {
327
- this.logger.info(`${chalk.italic("Starting")} task ${chalk.bold.cyan(task.name)} in phase ${chalk.bold.magenta(StartupPhase[phase])}`);
328
- try {
329
- await withTimeout(task.name, task.task, task.timeout);
330
- this.logger.info(`${chalk.italic("Completed")} task ${chalk.bold.cyan(task.name)} in phase ${chalk.bold.magenta(StartupPhase[phase])}`);
331
- } catch (error) {
332
- if (!this.isStartingUp) return;
333
- this.logger.error(`${chalk.italic("Failed")} task ${chalk.bold.cyan(task.name)} in phase ${chalk.bold.magenta(StartupPhase[phase])}:`, error);
334
- throw error;
335
- }
330
+ isAborted() {
331
+ return !this.isStartingUp;
336
332
  }
337
333
  /**
338
334
  * Aborts the startup sequence if it is currently running.
@@ -351,53 +347,54 @@ var CoordinatedStartup = class extends CoordinatedLifecycle {
351
347
  };
352
348
 
353
349
  //#endregion
354
- //#region src/node/HealthCheck.ts
350
+ //#region src/node/HealthResponder.ts
355
351
  const HTTP_OK = 200;
352
+ const DEFAULT_HEALTH_CHECK_PATH = "/health";
353
+ var HealthResponder = class {
354
+ path;
355
+ constructor(path) {
356
+ this.path = path ?? DEFAULT_HEALTH_CHECK_PATH;
357
+ }
358
+ tryRespond(req, res) {
359
+ if (req.method !== "GET" || req.url !== this.path) return false;
360
+ res.writeHead(HTTP_OK, { "Content-Type": "application/json" });
361
+ res.end(JSON.stringify({
362
+ status: "ok",
363
+ timestamp: Date.now()
364
+ }));
365
+ return true;
366
+ }
367
+ };
368
+
369
+ //#endregion
370
+ //#region src/node/HealthCheck.ts
356
371
  const HTTP_NOT_FOUND = 404;
357
372
  const DEFAULT_HEALTH_CHECK_PORT = 6967;
358
- const DEFAULT_HEALTH_CHECK_PATH = "/health";
359
- /**
360
- * HTTP server answering `GET` on the configured path with a JSON `{ status, timestamp }` body.
361
- */
362
373
  var HealthCheck = class HealthCheck {
363
- /** @internal */
364
374
  logger = new Logger("HealthCheck", { channel: "health" });
365
375
  port;
366
- path;
367
376
  host;
377
+ responder;
368
378
  server;
369
379
  constructor(shutdown, options) {
370
380
  this.port = options?.port ?? DEFAULT_HEALTH_CHECK_PORT;
371
- this.path = options?.path ?? DEFAULT_HEALTH_CHECK_PATH;
372
381
  this.host = options?.host;
382
+ this.responder = new HealthResponder(options?.path);
373
383
  shutdown.addTask(2, "stop-healthcheck-server", () => this.stop());
374
384
  }
375
- /**
376
- * Resolves the `healthCheck` option. `undefined` and `true` build the defaults, an object uses
377
- * its config, `false` returns `undefined`.
378
- */
385
+ get path() {
386
+ return this.responder.path;
387
+ }
379
388
  static fromOption(shutdown, option) {
380
389
  if (option === false) return void 0;
381
390
  return new HealthCheck(shutdown, typeof option === "object" ? option : void 0);
382
391
  }
383
- /**
384
- * Starts the health check server.
385
- * @returns Promise that resolves when the server is listening
386
- * @internal
387
- */
388
392
  async init() {
389
393
  return new Promise((resolve, reject) => {
390
394
  const server = createServer((req, res) => {
391
- if (req.method === "GET" && req.url === this.path) {
392
- res.writeHead(HTTP_OK, { "Content-Type": "application/json" });
393
- res.end(JSON.stringify({
394
- status: "ok",
395
- timestamp: Date.now()
396
- }));
397
- } else {
398
- res.writeHead(HTTP_NOT_FOUND, { "Content-Type": "application/json" });
399
- res.end(JSON.stringify({ status: "not found" }));
400
- }
395
+ if (this.responder.tryRespond(req, res)) return;
396
+ res.writeHead(HTTP_NOT_FOUND, { "Content-Type": "application/json" });
397
+ res.end(JSON.stringify({ status: "not found" }));
401
398
  });
402
399
  this.server = server;
403
400
  const onListenError = (err) => reject(err);
@@ -418,10 +415,6 @@ var HealthCheck = class HealthCheck {
418
415
  }
419
416
  });
420
417
  }
421
- /**
422
- * Stops the health check server.
423
- * @internal
424
- */
425
418
  stop() {
426
419
  const server = this.server;
427
420
  if (!server?.listening) return Promise.resolve();
@@ -651,9 +644,9 @@ var SubscriberLoader = class {
651
644
  this.bus.registerDefaults();
652
645
  const { directory } = this;
653
646
  if (directory) {
654
- this.bus.logger.info(chalk.bold(directory));
647
+ this.bus.logger.debug(chalk.bold(directory));
655
648
  await this.load(directory);
656
- this.bus.logger.utils.list([`${chalk.bold.magenta(this.bus.registeredCount)} subscribers`], chalk.bold.green("Loaded"));
649
+ this.bus.logger.utils.list([`${chalk.bold.magenta(this.bus.registeredCount)} subscribers`], chalk.bold.green("Loaded"), "debug");
657
650
  }
658
651
  if (!Envapter.isTest) await this.bus.verifyWebhooks();
659
652
  }
@@ -668,7 +661,7 @@ var SubscriberLoader = class {
668
661
  if (!this.isSubscriber(value)) continue;
669
662
  this.registerSubscriber(value);
670
663
  this.hmrHandler?.trackHandler(fullPath, value);
671
- this.bus.logger.utils.registration(value.name, relativePath);
664
+ this.bus.logger.utils.registration(value.name, relativePath, void 0, "trace");
672
665
  }
673
666
  });
674
667
  }
@@ -745,7 +738,7 @@ var CommandRegistry = class {
745
738
  utils.summary("Loaded commands", {
746
739
  global: this.globalCommands.length,
747
740
  "guild groups": this.guildCommands.size
748
- });
741
+ }, "debug");
749
742
  let slash = 0;
750
743
  let menu = 0;
751
744
  for (const command of this.loadedCommands) if (command.kind === "slash command") slash++;
@@ -753,16 +746,16 @@ var CommandRegistry = class {
753
746
  utils.block("Loaded commands", [...utils.entries(this.loadedCommands), ...utils.counts({
754
747
  "slash commands": slash,
755
748
  "context menus": menu
756
- })]);
749
+ })], "debug");
757
750
  }
758
751
  /** @internal */
759
752
  async refresh(shouldRefresh = true) {
760
753
  if (!shouldRefresh) {
761
- this.logger.info(chalk.italic("Command refresh cancelled."));
754
+ this.logger.debug(chalk.italic("Command refresh cancelled."));
762
755
  this.pendingEvents.clear();
763
756
  return;
764
757
  }
765
- this.logger.info(chalk.italic("Refreshing commands..."));
758
+ this.logger.debug(chalk.italic("Refreshing commands..."));
766
759
  for (const event of this.pendingEvents.values()) await this.hmrHandler?.handle(event);
767
760
  this.pendingEvents.clear();
768
761
  await this.setCommands();
@@ -803,15 +796,11 @@ var CommandRegistry = class {
803
796
  scope: meta.scope,
804
797
  ...meta.scope === "guild" && { guilds: meta.guilds }
805
798
  });
806
- if (this.loading) {
807
- this.loadedCommands.push({
808
- name: comp.name,
809
- from: formatFilePath(rel),
810
- kind
811
- });
812
- return;
813
- }
814
- this.logger.utils.registration(comp.name, rel, `${meta.scope} ${kind}`);
799
+ if (this.loading) this.loadedCommands.push({
800
+ name: comp.name,
801
+ from: formatFilePath(rel),
802
+ kind
803
+ });
815
804
  }
816
805
  unregisterCommand(ctor, artifacts) {
817
806
  const info = artifacts ?? this.ctorToCommand.get(ctor);
@@ -868,5 +857,5 @@ var CommandRegistry = class {
868
857
  };
869
858
 
870
859
  //#endregion
871
- export { CommandRegistry, CoordinatedShutdown, CoordinatedStartup, HealthCheck, Pluggable, ShutdownPhase, StartupPhase, SubscriberLoader, settleWithin };
860
+ export { CommandRegistry, CoordinatedShutdown, CoordinatedStartup, HealthCheck, HealthResponder, Pluggable, ShutdownPhase, StartupPhase, SubscriberLoader, settleWithin };
872
861
  //# sourceMappingURL=node-internal.index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"node-internal.index.mjs","names":["PHASE_ORDER"],"sources":["../src/node/Lifecycle/withTimeout.ts","../src/node/Lifecycle/CoordinatedLifecycle.ts","../src/node/Lifecycle/CoordinatedShutdown.ts","../src/node/Lifecycle/CoordinatedStartup.ts","../src/node/HealthCheck.ts","../src/node/Pluggable.ts","../src/node/subscribers/SubscriberLoader.ts","../src/node/commands/CommandRegistry.ts"],"sourcesContent":["import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nasync function raceTimer(\n work: Promise<unknown>,\n timeoutMs: number,\n onTimeout: (resolve: () => void, reject: (error: unknown) => void) => void\n): Promise<void> {\n let timer: NodeJS.Timeout | undefined;\n try {\n await Promise.race([\n work,\n new Promise<void>((resolve, reject) => {\n timer = setTimeout(() => onTimeout(resolve, reject), timeoutMs);\n })\n ]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\n/** @internal rejects with a `LifecycleTaskTimeout` when `run` outlasts the bound. */\nexport function withTimeout(name: string, run: () => Promise<void>, timeoutMs: number): Promise<void> {\n return raceTimer(run(), timeoutMs, (_, reject) => {\n reject(new SeedcordError(SeedcordErrorCode.LifecycleTaskTimeout, [name, timeoutMs]));\n });\n}\n\n/** @internal resolves when `work` settles or the bound elapses, whichever is first. */\nexport function settleWithin(work: Promise<unknown>, timeoutMs: number): Promise<void> {\n return raceTimer(work, timeoutMs, (resolve) => resolve());\n}\n","/*\n * Inspired by Akka Coordinated Shutdown: https://doc.akka.io/libraries/akka-core/current/coordinated-shutdown.html\n * and Lewis's implementation in a private repo elsewhere (https://github.com/Yomanz)\n */\n\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Logger } from '@seedcord/logger';\nimport chalk from 'chalk';\n\nimport { withTimeout } from './withTimeout';\n\nimport type { LifecycleTask } from './LifecycleTypes';\n\n/**\n * Base for the startup and shutdown coordinators. Runs phase-ordered tasks off a per-phase map.\n *\n * @internal\n */\nexport abstract class CoordinatedLifecycle<TPhase extends number> {\n protected readonly logger: Logger;\n protected readonly tasksMap = new Map<TPhase, LifecycleTask[]>();\n\n protected constructor(\n loggerName: string,\n protected readonly phaseOrder: TPhase[],\n protected readonly phaseEnum: Record<number, string>\n ) {\n this.logger = new Logger(loggerName, { channel: 'lifecycle' });\n this.phaseOrder.forEach((phase) => this.tasksMap.set(phase, []));\n }\n\n /**\n * Adds a task to `phase`. Tasks run in phase order, each bounded by `timeoutMs`.\n *\n * @param phase - The lifecycle phase to add the task to\n * @param taskName - Unique name for the task, used for logging and removal\n * @param task - Async function to execute during the phase\n * @param timeoutMs - Maximum time allowed for task execution in milliseconds\n */\n public addTask(phase: TPhase, taskName: string, task: () => Promise<void>, timeoutMs: number): void {\n if (!this.canAddTask()) return;\n\n const tasks = this.tasksMap.get(phase);\n if (!tasks) {\n throw new SeedcordError(SeedcordErrorCode.LifecycleUnknownPhase, [phase]);\n }\n\n tasks.push({ name: taskName, task, timeout: timeoutMs });\n this.logger.debug(\n `${chalk.italic('Added')} ${this.getTaskType()} task ${chalk.bold.cyan(taskName)} to phase ${chalk.bold.magenta(this.phaseEnum[phase])}`\n );\n }\n\n /**\n * Removes a lifecycle task from a specific phase.\n *\n * @param phase - The lifecycle phase to remove the task from\n * @param taskName - Name of the task to remove\n * @returns True if the task was found and removed, false otherwise\n */\n public removeTask(phase: TPhase, taskName: string): boolean {\n if (!this.canRemoveTask()) return false;\n\n const tasks = this.tasksMap.get(phase);\n if (!tasks) return false;\n\n const initialLength = tasks.length;\n const filteredTasks = tasks.filter((task) => task.name !== taskName);\n this.tasksMap.set(phase, filteredTasks);\n\n const removed = initialLength !== filteredTasks.length;\n if (removed) {\n this.logger.debug(\n `${chalk.italic('Removed')} ${this.getTaskType()} task ${chalk.bold.cyan(taskName)} from phase ${chalk.bold.magenta(this.phaseEnum[phase])}`\n );\n }\n\n return removed;\n }\n\n protected async runPhase(phase: TPhase): Promise<void> {\n const tasks = this.tasksMap.get(phase) ?? [];\n if (tasks.length === 0) {\n this.logger.debug(`No tasks to run in phase ${chalk.bold.magenta(this.phaseEnum[phase])}`);\n return;\n }\n\n this.logger.info(\n `${chalk.bold.yellow('Running')} ${this.getTaskType()} phase ${chalk.bold.magenta(this.phaseEnum[phase])} with ${chalk.bold.cyan(tasks.length)} tasks`\n );\n\n const results: PromiseSettledResult<void>[] = await this.executeTasksInPhase(phase, tasks);\n\n const failures = results.filter((r) => r.status === 'rejected').length;\n if (failures > 0) {\n // chalk here would leak ANSI codes into the serialized error message (the unknown-exception webhook)\n throw new SeedcordError(SeedcordErrorCode.LifecyclePhaseFailures, [this.phaseEnum[phase], failures]);\n }\n\n this.logger.info(\n `Phase ${chalk.bold.magenta(this.phaseEnum[phase])} ${chalk.bold.green('completed successfully')}`\n );\n }\n\n protected async runTaskWithTimeout(phase: TPhase, task: LifecycleTask): Promise<void> {\n this.logger.info(\n `${chalk.italic('Starting')} task ${chalk.bold.cyan(task.name)} in phase ${chalk.bold.magenta(this.phaseEnum[phase])}`\n );\n\n try {\n await withTimeout(task.name, task.task, task.timeout);\n\n this.logger.info(\n `${chalk.italic('Completed')} task ${chalk.bold.cyan(task.name)} in phase ${chalk.bold.magenta(this.phaseEnum[phase])}`\n );\n } catch (error) {\n this.logger.error(\n `${chalk.italic('Failed')} task ${chalk.bold.cyan(task.name)} in phase ${chalk.bold.magenta(this.phaseEnum[phase])}:`,\n error\n );\n throw error;\n }\n }\n\n protected abstract canAddTask(): boolean;\n protected abstract canRemoveTask(): boolean;\n protected abstract getTaskType(): string;\n protected abstract executeTasksInPhase(\n phase: TPhase,\n tasks: LifecycleTask[]\n ): Promise<PromiseSettledResult<void>[]>;\n}\n","import chalk from 'chalk';\n\nimport { ShutdownPhase } from '@src/lifecycle/phases';\n\nimport { CoordinatedLifecycle } from './CoordinatedLifecycle';\n\nimport type { LifecycleTask } from './LifecycleTypes';\n\nconst PHASE_ORDER: ShutdownPhase[] = [\n ShutdownPhase.Unbind,\n ShutdownPhase.Drain,\n ShutdownPhase.Disconnect,\n ShutdownPhase.Logout\n];\n\n// gives the logger's file sink time to flush before process.exit\nconst LOG_FLUSH_DELAY_MS = 3000;\n\n/**\n * Runs registered shutdown tasks across `ShutdownPhase` in order. Registers SIGINT and SIGTERM\n * handlers. Tasks within a phase run in parallel.\n */\nexport class CoordinatedShutdown extends CoordinatedLifecycle<ShutdownPhase> {\n private isShuttingDown = false;\n private hasShutdown = false;\n private exitCode = 0;\n private onSigTerm: (() => void) | null = null;\n private onSigInt: (() => void) | null = null;\n private startupGate?: Promise<void>;\n\n public constructor() {\n super('Shutdown', PHASE_ORDER, ShutdownPhase);\n\n this.registerSignalHandlers();\n }\n\n protected canAddTask(): boolean {\n return true;\n }\n\n protected canRemoveTask(): boolean {\n return true;\n }\n\n protected getTaskType(): string {\n return 'shutdown';\n }\n\n protected async executeTasksInPhase(\n phase: ShutdownPhase,\n tasks: LifecycleTask[]\n ): Promise<PromiseSettledResult<void>[]> {\n const promises = tasks.map((task) => this.runTaskWithTimeout(phase, task));\n return Promise.allSettled(promises);\n }\n\n private registerSignalHandlers(): void {\n this.onSigTerm = () => {\n this.logger.info(`Received ${chalk.yellow.bold('SIGTERM')} signal`);\n void this.run(0);\n };\n\n this.onSigInt = () => {\n this.logger.info(`Received ${chalk.yellow.bold('SIGINT')} signal`);\n void this.run(0);\n };\n\n process.on('SIGTERM', this.onSigTerm);\n process.on('SIGINT', this.onSigInt);\n }\n\n /** @internal */\n public removeSignalHandlers(): void {\n if (this.onSigTerm) {\n process.off('SIGTERM', this.onSigTerm);\n this.onSigTerm = null;\n }\n if (this.onSigInt) {\n process.off('SIGINT', this.onSigInt);\n this.onSigInt = null;\n }\n }\n\n /** @internal run() awaits this so boot finishes registering its dispose tasks first */\n public gateOnStartup(settled: Promise<void>): void {\n this.startupGate = settled;\n }\n\n /**\n * Adds a shutdown-phase task.\n *\n * @param phase - The shutdown phase to run the task in.\n * @param taskName - A descriptive name for the task.\n * @param task - The async function to run.\n * @param timeoutMs - Task timeout in ms. {@default `5000` }\n */\n public override addTask(phase: ShutdownPhase, taskName: string, task: () => Promise<void>, timeoutMs = 5000): void {\n super.addTask(phase, taskName, task, timeoutMs);\n }\n\n /** Removes a shutdown-phase task, returning whether one was removed. */\n public override removeTask(phase: ShutdownPhase, taskName: string): boolean {\n return super.removeTask(phase, taskName);\n }\n\n /**\n * Runs registered tasks across shutdown phases in `ShutdownPhase` order.\n * Tasks within each phase run in parallel.\n *\n * @param exitCode - Process exit code. {@default `0` }\n * @param exitProcess - Whether to exit the process after shutdown. {@default `true` }\n * @example\n * ```typescript\n * shutdown.addTask(ShutdownPhase.Disconnect, 'database', () => db.disconnect(), 5000);\n * await shutdown.run(0);\n * ```\n */\n public async run(exitCode = 0, exitProcess = true): Promise<void> {\n this.removeSignalHandlers();\n\n // a dev-mode run leaves the process alive, so a second call would re-execute every task\n if (this.hasShutdown || this.isShuttingDown) {\n this.logger.warn('Shutdown sequence already ran or is in progress');\n return;\n }\n\n this.isShuttingDown = true;\n this.exitCode = exitCode;\n this.logger.info(\n `${chalk.bold.yellow('Starting')} coordinated shutdown with exit code ${chalk.bold.cyan(exitCode)}`\n );\n\n try {\n if (this.startupGate) await this.startupGate;\n const failures: unknown[] = [];\n for (const phase of PHASE_ORDER) {\n // run every phase so a mid-shutdown failure still attempts the later teardowns\n try {\n await this.runPhase(phase);\n } catch (error) {\n failures.push(error);\n }\n }\n\n if (failures.length > 0) {\n this.logger.error(`${chalk.bold.red('Coordinated shutdown failed')}`, ...failures);\n } else {\n this.logger.info(`${chalk.bold.green('Coordinated shutdown completed')} successfully`);\n }\n } finally {\n this.hasShutdown = true;\n if (exitProcess) {\n this.logger.info(`${chalk.bold.red('Exiting')} process with code ${chalk.bold.cyan(this.exitCode)}`);\n setTimeout(() => {\n process.exit(this.exitCode);\n }, LOG_FLUSH_DELAY_MS);\n } else {\n this.logger.info(`${chalk.bold.yellow('Skipping')} process exit (dev mode)`);\n this.isShuttingDown = false;\n }\n }\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport chalk from 'chalk';\n\nimport { StartupPhase } from '@src/lifecycle/phases';\n\nimport { CoordinatedLifecycle } from './CoordinatedLifecycle';\nimport { withTimeout } from './withTimeout';\n\nimport type { LifecycleTask } from './LifecycleTypes';\n\nconst PHASE_ORDER: StartupPhase[] = [StartupPhase.Configuration, StartupPhase.Login, StartupPhase.Ready];\n\n/**\n * Runs registered startup tasks across `StartupPhase` in order. Tasks within a phase run in parallel.\n */\nexport class CoordinatedStartup extends CoordinatedLifecycle<StartupPhase> {\n private isStartingUp = false;\n private hasStarted = false;\n\n public constructor() {\n super('Startup', PHASE_ORDER, StartupPhase);\n }\n\n /**\n * Adds a startup-phase task.\n *\n * @param phase - The startup phase to run the task in.\n * @param taskName - A descriptive name for the task.\n * @param task - The async function to run.\n * @param timeoutMs - Task timeout in ms. {@default `10000` }\n */\n public override addTask(\n phase: StartupPhase,\n taskName: string,\n task: () => Promise<void>,\n timeoutMs = 10_000\n ): void {\n super.addTask(phase, taskName, task, timeoutMs);\n }\n\n protected canAddTask(): boolean {\n if (this.hasStarted) {\n throw new SeedcordError(SeedcordErrorCode.LifecycleAddAfterCompletion);\n }\n\n if (this.isStartingUp) {\n throw new SeedcordError(SeedcordErrorCode.LifecycleAddDuringRun);\n }\n\n return true;\n }\n\n protected canRemoveTask(): boolean {\n if (this.isStartingUp) {\n throw new SeedcordError(SeedcordErrorCode.LifecycleRemoveDuringRun);\n }\n\n return true;\n }\n\n protected getTaskType(): string {\n return 'startup';\n }\n\n protected async executeTasksInPhase(\n phase: StartupPhase,\n tasks: LifecycleTask[]\n ): Promise<PromiseSettledResult<void>[]> {\n const promises = tasks.map((task) => this.runTaskWithTimeout(phase, task));\n return Promise.allSettled(promises);\n }\n\n /**\n * Runs the registered tasks across startup phases in `StartupPhase` order. Each phase completes\n * before the next begins, and tasks within a phase run concurrently.\n *\n * @throws {@link SeedcordError} if a startup task throws.\n */\n public async run(): Promise<void> {\n if (this.hasStarted) {\n this.logger.warn('Startup sequence has already completed');\n return;\n }\n\n if (this.isStartingUp) {\n this.logger.warn('Startup sequence already in progress');\n return;\n }\n\n this.isStartingUp = true;\n this.logger.info(`${chalk.bold.green('Starting')} coordinated startup sequence`);\n\n try {\n for (const phase of PHASE_ORDER) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- abort() can flip isStartingUp to false mid-loop from the cli\n if (!this.isStartingUp) {\n this.logger.warn('Startup sequence aborted');\n return;\n }\n await this.runPhase(phase);\n }\n\n this.hasStarted = true;\n this.logger.info(`${chalk.bold.green('Coordinated startup completed')} successfully`);\n } catch (error) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- abort() can flip isStartingUp to false before this catch runs\n if (!this.isStartingUp) {\n this.logger.warn('Startup sequence aborted during error handling');\n return;\n }\n this.logger.error(`${chalk.bold.red('Coordinated startup failed')}`);\n throw error;\n } finally {\n this.isStartingUp = false;\n }\n }\n\n protected override async runTaskWithTimeout(phase: StartupPhase, task: LifecycleTask): Promise<void> {\n this.logger.info(\n `${chalk.italic('Starting')} task ${chalk.bold.cyan(task.name)} in phase ${chalk.bold.magenta(StartupPhase[phase])}`\n );\n\n try {\n await withTimeout(task.name, task.task, task.timeout);\n\n this.logger.info(\n `${chalk.italic('Completed')} task ${chalk.bold.cyan(task.name)} in phase ${chalk.bold.magenta(StartupPhase[phase])}`\n );\n } catch (error) {\n if (!this.isStartingUp) {\n return;\n }\n\n this.logger.error(\n `${chalk.italic('Failed')} task ${chalk.bold.cyan(task.name)} in phase ${chalk.bold.magenta(StartupPhase[phase])}:`,\n error\n );\n throw error;\n }\n }\n\n /**\n * Aborts the startup sequence if it is currently running.\n */\n public abort(): void {\n if (!this.isStartingUp) return;\n\n this.isStartingUp = false;\n this.logger.warn('Aborting coordinated startup sequence');\n }\n\n public get isReady(): boolean {\n return this.hasStarted;\n }\n\n public get isRunning(): boolean {\n return this.isStartingUp;\n }\n}\n","import { createServer } from 'node:http';\n\nimport { Logger, paint } from '@seedcord/logger';\n\nimport { ShutdownPhase } from '@src/lifecycle/phases';\n\nimport type { CoordinatedShutdown } from './Lifecycle/CoordinatedShutdown';\nimport type { HealthCheckConfig, HealthCheckOption } from '@seedcord/types';\nimport type { IncomingMessage, Server, ServerResponse } from 'node:http';\n\nconst HTTP_OK = 200;\nconst HTTP_NOT_FOUND = 404;\n\nconst DEFAULT_HEALTH_CHECK_PORT = 6967;\nconst DEFAULT_HEALTH_CHECK_PATH = '/health';\n\n/**\n * HTTP server answering `GET` on the configured path with a JSON `{ status, timestamp }` body.\n */\nexport class HealthCheck {\n /** @internal */\n public readonly logger = new Logger('HealthCheck', { channel: 'health' });\n\n public readonly port: number;\n public readonly path: string;\n public readonly host: string | undefined;\n\n private server?: Server;\n\n constructor(shutdown: CoordinatedShutdown, options?: HealthCheckConfig) {\n this.port = options?.port ?? DEFAULT_HEALTH_CHECK_PORT;\n this.path = options?.path ?? DEFAULT_HEALTH_CHECK_PATH;\n this.host = options?.host;\n\n shutdown.addTask(ShutdownPhase.Drain, 'stop-healthcheck-server', () => this.stop());\n }\n\n /**\n * Resolves the `healthCheck` option. `undefined` and `true` build the defaults, an object uses\n * its config, `false` returns `undefined`.\n */\n public static fromOption(shutdown: CoordinatedShutdown, option?: HealthCheckOption): HealthCheck | undefined {\n if (option === false) return undefined;\n return new HealthCheck(shutdown, typeof option === 'object' ? option : undefined);\n }\n\n /**\n * Starts the health check server.\n * @returns Promise that resolves when the server is listening\n * @internal\n */\n public async init(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n if (req.method === 'GET' && req.url === this.path) {\n res.writeHead(HTTP_OK, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ status: 'ok', timestamp: Date.now() }));\n } else {\n res.writeHead(HTTP_NOT_FOUND, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ status: 'not found' }));\n }\n });\n this.server = server;\n\n const onListenError = (err: Error): void => reject(err);\n server.on('error', onListenError);\n\n server.once('listening', () => {\n // a late error would reject an already-settled promise, and no 'error' listener at all crashes the process\n server.removeListener('error', onListenError);\n server.on('error', (err) => this.logger.error('Health check server error', err));\n\n // binds all interfaces, so log an address a browser can open\n const address = this.host ?? 'localhost';\n this.logger.info(\n `${paint.mint.bold('✔︎')} Health check server listening on ${paint.sky(`http://${address}:${this.port}${this.path}`)}`\n );\n resolve();\n });\n\n if (this.host) {\n this.logger.debug(`Binding health check server to ${this.host}`);\n server.listen(this.port, this.host);\n } else {\n this.logger.debug('Binding health check server to all interfaces');\n server.listen(this.port);\n }\n });\n }\n\n /**\n * Stops the health check server.\n * @internal\n */\n public stop(): Promise<void> {\n const server = this.server;\n // close() on a non-listening server invokes its callback with ERR_SERVER_NOT_RUNNING and\n // never fires 'close', so without this guard the promise would hang the shutdown phase.\n if (!server?.listening) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n // settle only in the callback, a 'close'-event resolve would swallow the callback's error\n server.close((err) => {\n if (err) {\n reject(err);\n return;\n }\n this.logger.info(paint.coral.bold('Health check server stopped'));\n resolve();\n });\n });\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { FRAMEWORK_CHANNELS, Logger } from '@seedcord/logger';\n\nimport { StartupPhase } from '@src/lifecycle/phases';\nimport { resolvedLifecycleSpecOf } from '@src/plugin/Plugin';\n\nimport { withTimeout } from './Lifecycle/withTimeout';\n\nimport type { REST } from '@discordjs/rest';\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { CoordinatedShutdown } from '@node/Lifecycle/CoordinatedShutdown';\nimport type { CoordinatedStartup } from '@node/Lifecycle/CoordinatedStartup';\nimport type { Config, IRateLimiter } from '@seedcord/types';\nimport type { ShutdownPhase } from '@src/lifecycle/phases';\nimport type { ChannelKeyAssert, Runtime, RuntimeAssert, Transport, TransportAssert } from '@src/plugin/options';\nimport type { CoreParamAssert, PluginArgs, PluginCtor, PluginLike } from '@src/plugin/Plugin';\nimport type { Bus } from '@subscribers/Bus';\n\ninterface Attachment {\n readonly key: string;\n readonly instance: PluginLike;\n}\n\nconst RESERVED_KEYS: ReadonlySet<string> = new Set(FRAMEWORK_CHANNELS);\n\n/**\n * Base class for a plugin host, a transport `Seedcord` class.\n *\n * Plugins are attached during configuration and initialized during startup, sequentially in attach\n * order within each phase.\n */\n// no defaults, a default runtime of the full union contains 'edge' and RuntimeAssert rejects every plugin on that\nexport abstract class Pluggable<BotT extends Transport, BotRt extends Runtime> implements CoreBase {\n public abstract readonly config: Config;\n public abstract readonly rest: REST;\n public abstract readonly rateLimiter: IRateLimiter;\n public abstract readonly bus: Bus;\n\n /** @see {@link CoordinatedShutdown} */\n public readonly shutdown: CoordinatedShutdown;\n\n /** @see {@link CoordinatedStartup} */\n public readonly startup: CoordinatedStartup;\n\n protected isInitialized = false;\n protected startFailed = false;\n protected readonly plugins: PluginLike[] = [];\n\n private readonly pluginLogger = new Logger('Plugins', { channel: 'plugins' });\n\n private readonly attachments: Attachment[] = [];\n private readonly completedInits = new Set<Attachment>();\n private readonly disposePhases = new Set<ShutdownPhase>();\n private pluginTasksRegistered = false;\n\n private static isInstantiated = false;\n private static liveShutdown?: CoordinatedShutdown | undefined;\n\n constructor(shutdown: CoordinatedShutdown, startup: CoordinatedStartup) {\n if (Pluggable.isInstantiated) {\n // the caller constructed this shutdown, its signal handlers leak unless dropped here\n shutdown.removeSignalHandlers();\n throw new SeedcordError(SeedcordErrorCode.CoreSingletonViolation);\n }\n\n Pluggable.isInstantiated = true;\n Pluggable.liveShutdown = shutdown;\n this.shutdown = shutdown;\n this.startup = startup;\n }\n\n /** @internal */\n protected async init(): Promise<this> {\n if (this.isInitialized) return this;\n // a rerun after a failed startup would re-init the rolled-back plugins\n if (this.startFailed) throw new SeedcordError(SeedcordErrorCode.LifecycleRestartAfterFailure);\n\n this.registerPluginTasks();\n\n const startupSettled: PromiseWithResolvers<void> = Promise.withResolvers();\n this.shutdown.gateOnStartup(startupSettled.promise);\n\n try {\n await this.startup.run();\n } catch (caught) {\n await this.rollback();\n throw caught;\n } finally {\n startupSettled.resolve();\n }\n\n this.isInitialized = true;\n return this;\n }\n\n /** @internal codegen reads these to emit the `Core` augmentation */\n public get pluginKeys(): readonly string[] {\n return this.attachments.map((attachment) => attachment.key);\n }\n\n /** @internal so the next host can construct */\n protected static reset(): void {\n Pluggable.liveShutdown?.removeSignalHandlers();\n Pluggable.liveShutdown = undefined;\n Pluggable.isInstantiated = false;\n }\n\n /**\n * Attaches a plugin to this instance.\n *\n * The plugin initializes during startup, after every plugin attached before it, and becomes\n * available as a property on `core`. `seedcord codegen` writes the `Core` augmentation that\n * types it.\n *\n * A plugin declaring a `transport` or `runtime` this host does not run is a compile error on\n * this call. An edge host takes no plugins at all. A plugin constructor narrowing its first\n * parameter past `CoreBase` is a compile error here too. Read the transport `Core` off `this.core`.\n *\n * @typeParam Key - The property name for accessing the plugin\n * @typeParam Ctor - The plugin constructor type\n * @param key - Property name to access the plugin instance\n * @param Plugin - Plugin constructor class\n * @param args - Additional arguments to pass to the plugin constructor\n * @returns This instance with the plugin attached as a typed property\n * @throws A **SeedcordError** When called after initialization or if key already exists or is reserved\n * @example\n * ```typescript\n * seedcord.attach('db', Mongoose, { uri: 'mongodb://...', name: 'seedcord', dir: ... })\n * ```\n */\n public attach<Key extends string, Ctor extends PluginCtor>(\n this: this,\n key: ChannelKeyAssert<Key>,\n Plugin: Ctor &\n TransportAssert<InstanceType<Ctor>, BotT> &\n RuntimeAssert<InstanceType<Ctor>, BotRt> &\n CoreParamAssert<Ctor>,\n ...args: PluginArgs<Ctor>\n ): this & Record<Key, InstanceType<Ctor>> {\n if (this.isInitialized) {\n throw new SeedcordError(SeedcordErrorCode.CorePluginAfterInit);\n }\n // several reserved channels are also members on a host, which the next check would report first\n if (RESERVED_KEYS.has(key)) {\n throw new SeedcordError(SeedcordErrorCode.CorePluginReservedChannel, [key]);\n }\n if (key in this) {\n throw new SeedcordError(SeedcordErrorCode.CorePluginKeyExists, [key]);\n }\n\n const instance = new Plugin(this, ...args);\n instance.logger.setChannel(key);\n this.plugins.push(instance);\n this.attachments.push({ key, instance });\n\n return Object.assign(this, { [key]: instance } as Record<Key, InstanceType<Ctor>>);\n }\n\n // one combined task per phase keeps plugin inits sequential while the phase's other tasks run concurrently\n private registerPluginTasks(): void {\n if (this.pluginTasksRegistered) return;\n this.pluginTasksRegistered = true;\n\n const groups = new Map<StartupPhase, Attachment[]>();\n for (const attachment of this.attachments) {\n const phase = resolvedLifecycleSpecOf(attachment.instance).init.phase;\n const group = groups.get(phase) ?? [];\n group.push(attachment);\n groups.set(phase, group);\n }\n\n for (const [phase, group] of groups) {\n // Ready inits run in the combined Ready task, before the ready hooks\n if (phase === StartupPhase.Ready) continue;\n const budget = group.reduce((sum, a) => sum + resolvedLifecycleSpecOf(a.instance).init.timeout, 0);\n this.startup.addTask(phase, 'plugins-init', () => this.runInits(group), budget);\n }\n\n this.registerReadyTask(groups.get(StartupPhase.Ready) ?? []);\n }\n\n private async runInits(group: readonly Attachment[]): Promise<void> {\n for (const attachment of group) {\n const { key, instance } = attachment;\n const spec = resolvedLifecycleSpecOf(instance);\n\n instance.logger.utils.initialization(key, 'start');\n await withTimeout(`Plugin (${key})`, () => instance.init(), spec.init.timeout);\n instance.logger.utils.initialization(key, 'end');\n\n this.completedInits.add(attachment);\n if (instance.dispose) this.registerDisposeTask(spec.dispose.phase);\n }\n }\n\n private registerReadyTask(readyInits: readonly Attachment[]): void {\n const steps = this.attachments.reduce<{ key: string; run: () => Promise<void>; timeout: number }[]>(\n (acc, a) => {\n const ready = a.instance.ready?.bind(a.instance);\n if (ready) {\n acc.push({\n key: a.key,\n run: ready,\n timeout: resolvedLifecycleSpecOf(a.instance).ready.timeout\n });\n }\n return acc;\n },\n []\n );\n if (readyInits.length === 0 && steps.length === 0) return;\n\n const budget =\n readyInits.reduce((sum, a) => sum + resolvedLifecycleSpecOf(a.instance).init.timeout, 0) +\n steps.reduce((sum, step) => sum + step.timeout, 0);\n this.startup.addTask(\n StartupPhase.Ready,\n 'plugins-ready',\n async () => {\n await this.runInits(readyInits);\n for (const step of steps) {\n await withTimeout(`Plugin:${step.key}:ready`, step.run, step.timeout);\n }\n },\n budget\n );\n }\n\n private registerDisposeTask(phase: ShutdownPhase): void {\n if (this.disposePhases.has(phase)) return;\n this.disposePhases.add(phase);\n\n // registered once per phase, later inits of that phase run in the same task\n const budget = this.attachments.reduce((sum, a) => {\n const spec = resolvedLifecycleSpecOf(a.instance);\n return a.instance.dispose && spec.dispose.phase === phase ? sum + spec.dispose.timeout : sum;\n }, 0);\n this.shutdown.addTask(phase, 'plugins-dispose', () => this.runDisposals(phase), budget);\n }\n\n private async runDisposals(phase: ShutdownPhase): Promise<void> {\n const failures: unknown[] = [];\n // keep disposing the rest even when one fails\n await this.disposeCompleted(phase, (caught) => failures.push(caught));\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1) throw new AggregateError(failures, 'plugin dispose failures');\n }\n\n private async disposeCompleted(\n phase: ShutdownPhase | undefined,\n onError: (caught: unknown) => void\n ): Promise<void> {\n for (const attachment of [...this.attachments].reverse()) {\n if (!this.completedInits.has(attachment)) continue;\n const dispose = attachment.instance.dispose?.bind(attachment.instance);\n if (!dispose) continue;\n const spec = resolvedLifecycleSpecOf(attachment.instance);\n if (phase !== undefined && spec.dispose.phase !== phase) continue;\n\n try {\n await withTimeout(`Plugin:${attachment.key}:dispose`, dispose, spec.dispose.timeout);\n } catch (caught) {\n onError(caught);\n }\n }\n }\n\n private async rollback(): Promise<void> {\n this.startFailed = true;\n // log rollback dispose failures so they do not hide the startup error\n await this.disposeCompleted(undefined, (caught) => this.pluginLogger.warn('rollback dispose failed', caught));\n // prevents re-dispose when shutdown runs after rollback\n this.completedInits.clear();\n }\n}\n","import { traverseDirectory } from '@seedcord/utils/node';\nimport chalk from 'chalk';\nimport { Envapter } from 'envapt';\n\nimport { HmrModuleHandler } from '@hmr/HmrModuleHandler';\nimport { SubscribeMetadataKey } from '@src/metadataKeys';\nimport { registrationFor, Subscriber } from '@subscribers/index';\n\nimport type { HmrAware, HmrUpdateEvent } from '@seedcord/types';\nimport type { Initializeable } from '@src/plugin/Plugin';\nimport type { SubscribeMetadataEntry } from '@subscribers/decorators/Subscribe';\nimport type { StoredSubscriberCtor, Bus } from '@subscribers/index';\nimport type { SubscriptionKey } from '@subscribers/types/Subscriptions';\n\ntype SubscriberArtifact = SubscriptionKey[];\n\n/**\n * Loads subscribers off the filesystem into a {@link Bus} and stores their hot-reload wiring. Node\n * only, a bundled isolate registers from the manifest instead.\n *\n * @internal\n */\nexport class SubscriberLoader implements Initializeable, HmrAware {\n private isInitialized = false;\n private readonly hmrHandler?: HmrModuleHandler<StoredSubscriberCtor, void, SubscriberArtifact>;\n\n constructor(\n private readonly bus: Bus,\n private readonly directory: string | null\n ) {\n if (!this.directory) return;\n if (!Envapter.isDevelopment && !Envapter.isTest) return;\n\n this.hmrHandler = new HmrModuleHandler({\n handlersDir: this.directory,\n isHandler: this.isSubscriber.bind(this),\n registerHandler: this.registerSubscriber.bind(this),\n unregisterHandler: this.unregisterSubscriber.bind(this),\n getArtifacts: this.getArtifacts.bind(this),\n logger: this.bus.logger\n });\n }\n\n /** @internal */\n public async init(): Promise<void> {\n if (this.isInitialized) return;\n this.isInitialized = true;\n\n this.bus.registerDefaults();\n\n const { directory } = this;\n if (directory) {\n this.bus.logger.info(chalk.bold(directory));\n await this.load(directory);\n this.bus.logger.utils.list(\n [`${chalk.bold.magenta(this.bus.registeredCount)} subscribers`],\n chalk.bold.green('Loaded')\n );\n }\n\n if (!Envapter.isTest) await this.bus.verifyWebhooks();\n }\n\n /** @internal */\n public async onHmr(event: HmrUpdateEvent): Promise<void> {\n if (this.hmrHandler) await this.hmrHandler.handle(event);\n }\n\n private async load(dir: string): Promise<void> {\n await traverseDirectory(dir, (fullPath, relativePath, imported) => {\n for (const exportName of Object.keys(imported)) {\n const value = imported[exportName];\n if (!this.isSubscriber(value)) continue;\n\n this.registerSubscriber(value);\n this.hmrHandler?.trackHandler(fullPath, value);\n this.bus.logger.utils.registration(value.name, relativePath);\n }\n });\n }\n\n private registerSubscriber(ctor: StoredSubscriberCtor): void {\n this.bus.register(registrationFor(ctor));\n }\n\n private unregisterSubscriber(ctor: StoredSubscriberCtor, artifacts?: SubscriberArtifact): void {\n this.bus.unregister(ctor, artifacts);\n }\n\n private getArtifacts(ctor: StoredSubscriberCtor): SubscriberArtifact {\n const meta = Reflect.getMetadata(SubscribeMetadataKey, ctor) as SubscribeMetadataEntry;\n return [meta.subscriber];\n }\n\n private isSubscriber(value: unknown): value is StoredSubscriberCtor {\n if (typeof value !== 'function') return false;\n return value.prototype instanceof Subscriber && Reflect.hasMetadata(SubscribeMetadataKey, value);\n }\n}\n","import { resolve } from 'node:path';\n\nimport { SlashCommandBuilder } from '@discordjs/builders';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Logger, paint } from '@seedcord/logger';\nimport { formatFilePath } from '@seedcord/utils';\nimport { traverseDirectory } from '@seedcord/utils/node';\nimport chalk from 'chalk';\nimport { Routes } from 'discord-api-types/v10';\nimport { Envapter } from 'envapt';\n\nimport { BuilderComponent } from '@components/Component';\nimport { getDevChannel } from '@hmr/devChannel';\nimport { HmrModuleHandler } from '@hmr/HmrModuleHandler';\nimport { contextMenuLeaves } from '@src/commands/contextMenuLeaves';\nimport { slashRouteLeaves } from '@src/commands/slashRouteLeaves';\nimport { CommandMetadataKey } from '@src/metadataKeys';\n\nimport type { CommandMeta } from '@decorators/Command';\nimport type { REST } from '@discordjs/rest';\nimport type { HmrAware, HmrUpdateEvent } from '@seedcord/types';\nimport type { ContextMenuLeaves } from '@src/commands/contextMenuLeaves';\nimport type { CommandBuilder, DeployResult } from '@src/commands/types';\nimport type { Initializeable } from '@src/plugin/Plugin';\nimport type { APIApplicationCommand } from 'discord-api-types/v10';\n\ntype CommandCtor = new () => BuilderComponent<'command' | 'context_menu'>;\n\n/** @internal */\nexport interface CommandRegistryOptions {\n readonly dir: string;\n readonly rest: REST;\n /** Called at deploy time, because the application id only resolves after login. */\n readonly applicationId: () => string;\n readonly onDeployed?: (result: DeployResult) => void;\n}\n\ninterface CommandArtifact {\n name: string;\n scope: 'global' | 'guild';\n guilds?: string[];\n}\n\nfunction indexById(commands: readonly APIApplicationCommand[]): Map<string, APIApplicationCommand> {\n return new Map(commands.map((command) => [command.id, command]));\n}\n\n/**\n * Scans the command directory, builds each command, and PUTs the global and guild scopes to Discord.\n *\n * @internal\n */\nexport class CommandRegistry implements Initializeable, HmrAware {\n private readonly logger = new Logger('Commands', { channel: 'commands' });\n private isInitialised = false;\n\n public readonly globalCommands: CommandBuilder[] = [];\n public readonly guildCommands = new Map<string, CommandBuilder[]>();\n\n private readonly ctorToCommand = new Map<CommandCtor, CommandArtifact>();\n\n // batched during bulk load, hmr registrations log inline\n private loading = false;\n private readonly loadedCommands: { name: string; from: string; kind: 'slash command' | 'context menu' }[] = [];\n\n private readonly hmrHandler?: HmrModuleHandler<CommandCtor, void, CommandArtifact | undefined>;\n private readonly pendingEvents = new Map<string, HmrUpdateEvent>();\n\n public constructor(private readonly options: CommandRegistryOptions) {\n if (!options.dir) {\n throw new SeedcordError(SeedcordErrorCode.CoreControllerPathMissing, ['CommandRegistry', 'commands']);\n }\n\n if (!Envapter.isDevelopment && !Envapter.isTest) return;\n this.hmrHandler = new HmrModuleHandler<CommandCtor, void, CommandArtifact | undefined>({\n handlersDir: options.dir,\n isHandler: this.isCommandClass.bind(this),\n registerHandler: this.registerCommand.bind(this),\n unregisterHandler: this.unregisterCommand.bind(this),\n getArtifacts: this.getArtifacts.bind(this),\n logger: this.logger\n });\n }\n\n private getArtifacts(ctor: CommandCtor): CommandArtifact | undefined {\n return this.ctorToCommand.get(ctor);\n }\n\n /** @internal */\n public async init(): Promise<void> {\n if (this.isInitialised) return;\n this.isInitialised = true;\n\n this.loading = true;\n this.loadedCommands.length = 0;\n try {\n await this.loadCommands(this.options.dir);\n } finally {\n this.loading = false;\n }\n\n this.reportLoad();\n\n getDevChannel()?.on('seedcord:refresh-commands', (data) => {\n void this.refresh(data.shouldRefresh);\n });\n }\n\n private reportLoad(): void {\n const { utils } = this.logger;\n\n utils.summary('Loaded commands', {\n global: this.globalCommands.length,\n 'guild groups': this.guildCommands.size\n });\n\n let slash = 0;\n let menu = 0;\n for (const command of this.loadedCommands) {\n if (command.kind === 'slash command') slash++;\n else menu++;\n }\n\n utils.block('Loaded commands', [\n ...utils.entries(this.loadedCommands),\n ...utils.counts({ 'slash commands': slash, 'context menus': menu })\n ]);\n }\n\n /** @internal */\n public async refresh(shouldRefresh = true): Promise<void> {\n if (!shouldRefresh) {\n this.logger.info(chalk.italic('Command refresh cancelled.'));\n this.pendingEvents.clear();\n return;\n }\n\n this.logger.info(chalk.italic('Refreshing commands...'));\n for (const event of this.pendingEvents.values()) {\n await this.hmrHandler?.handle(event);\n }\n this.pendingEvents.clear();\n await this.setCommands();\n }\n\n /** @internal */\n public async onHmr(event: HmrUpdateEvent): Promise<void> {\n if (event.file.startsWith(resolve(process.cwd(), this.options.dir))) {\n this.pendingEvents.delete(event.file);\n this.pendingEvents.set(event.file, event);\n getDevChannel()?.send('seedcord:commands-update-prompt', {\n files: [...this.pendingEvents.keys()].map((f) => formatFilePath(f))\n });\n } else {\n await this.hmrHandler?.handle(event);\n }\n }\n\n private async loadCommands(dir: string): Promise<void> {\n await traverseDirectory(dir, (fullPath, rel, mod) => {\n for (const exported of Object.values(mod))\n if (this.isCommandClass(exported)) {\n this.registerCommand(exported, rel);\n this.hmrHandler?.trackHandler(fullPath, exported);\n }\n });\n }\n\n private isCommandClass(obj: unknown): obj is CommandCtor {\n if (typeof obj !== 'function') return false;\n return obj.prototype instanceof BuilderComponent && Reflect.hasMetadata(CommandMetadataKey, obj);\n }\n\n private registerCommand(ctor: CommandCtor, rel: string): void {\n const meta = Reflect.getMetadata(CommandMetadataKey, ctor) as CommandMeta | undefined;\n\n if (!meta) return;\n\n const instance = new ctor();\n const comp = instance.component;\n const kind = comp instanceof SlashCommandBuilder ? 'slash command' : 'context menu';\n\n if (meta.scope === 'global') {\n this.globalCommands.push(comp);\n } else {\n for (const g of meta.guilds) {\n const arr = this.guildCommands.get(g) ?? [];\n arr.push(comp);\n this.guildCommands.set(g, arr);\n }\n }\n\n this.ctorToCommand.set(ctor, {\n name: comp.name,\n scope: meta.scope,\n ...(meta.scope === 'guild' && { guilds: meta.guilds })\n });\n\n if (this.loading) {\n this.loadedCommands.push({ name: comp.name, from: formatFilePath(rel), kind });\n return;\n }\n\n this.logger.utils.registration(comp.name, rel, `${meta.scope} ${kind}`);\n }\n\n private unregisterCommand(ctor: CommandCtor, artifacts?: CommandArtifact): void {\n const info = artifacts ?? this.ctorToCommand.get(ctor);\n if (!info) return;\n\n if (info.scope === 'global') {\n const idx = this.globalCommands.findIndex((c) => c.name === info.name);\n if (idx !== -1) this.globalCommands.splice(idx, 1);\n } else {\n for (const g of info.guilds ?? []) {\n const arr = this.guildCommands.get(g);\n if (arr) {\n const idx = arr.findIndex((c) => c.name === info.name);\n if (idx !== -1) arr.splice(idx, 1);\n }\n }\n }\n this.ctorToCommand.delete(ctor);\n }\n\n /** @internal */\n public async setCommands(): Promise<DeployResult> {\n const result: DeployResult = { global: new Map(), guilds: new Map() };\n const appId = this.options.applicationId();\n\n if (this.globalCommands.length > 0) {\n const deployed = await this.put(Routes.applicationCommands(appId), this.globalCommands);\n result.global = indexById(deployed);\n const tag = this.globalCommands.length === 1 ? 'command' : 'commands';\n this.logger.utils.block(\n `Deployed ${this.globalCommands.length} global ${tag}`,\n this.logger.utils.wrap(this.globalCommands.map((command) => command.name)),\n 'info'\n );\n }\n\n for (const [guildId, commands] of this.guildCommands.entries()) {\n const deployed = await this.put(Routes.applicationGuildCommands(appId, guildId), commands);\n result.guilds.set(guildId, indexById(deployed));\n const tag = commands.length === 1 ? 'command' : 'commands';\n this.logger.utils.block(\n `Deployed ${commands.length} ${tag} to ${paint.amber.bold(guildId)}`,\n this.logger.utils.wrap(commands.map((command) => command.name)),\n 'info'\n );\n }\n\n this.options.onDeployed?.(result);\n return result;\n }\n\n private async put(route: `/${string}`, commands: readonly CommandBuilder[]): Promise<APIApplicationCommand[]> {\n const body = commands.map((command) => command.toJSON());\n // justified: the bulk-overwrite routes return the deployed command array\n return (await this.options.rest.put(route, { body })) as APIApplicationCommand[];\n }\n\n /** Every registered builder, global first. A guild command in N guilds appears once per guild. @internal */\n public allCommands(): CommandBuilder[] {\n return [...this.globalCommands, ...this.guildCommands.values()].flat();\n }\n\n /** @internal */\n public routeLeaves(): Set<string> {\n return slashRouteLeaves(this.allCommands());\n }\n\n /** @internal */\n public contextMenuLeaves(): ContextMenuLeaves {\n return contextMenuLeaves(this.allCommands());\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"node-internal.index.mjs","names":["PHASE_ORDER"],"sources":["../src/node/Lifecycle/withTimeout.ts","../src/node/Lifecycle/CoordinatedLifecycle.ts","../src/node/Lifecycle/CoordinatedShutdown.ts","../src/node/Lifecycle/CoordinatedStartup.ts","../src/node/HealthResponder.ts","../src/node/HealthCheck.ts","../src/node/Pluggable.ts","../src/node/subscribers/SubscriberLoader.ts","../src/node/commands/CommandRegistry.ts"],"sourcesContent":["import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nasync function raceTimer(\n work: Promise<unknown>,\n timeoutMs: number,\n onTimeout: (resolve: () => void, reject: (error: unknown) => void) => void\n): Promise<void> {\n let timer: NodeJS.Timeout | undefined;\n try {\n await Promise.race([\n work,\n new Promise<void>((resolve, reject) => {\n timer = setTimeout(() => onTimeout(resolve, reject), timeoutMs);\n })\n ]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n\n/** @internal rejects with a `LifecycleTaskTimeout` when `run` outlasts the bound. */\nexport function withTimeout(name: string, run: () => Promise<void>, timeoutMs: number): Promise<void> {\n return raceTimer(run(), timeoutMs, (_, reject) => {\n reject(new SeedcordError(SeedcordErrorCode.LifecycleTaskTimeout, [name, timeoutMs]));\n });\n}\n\n/** @internal resolves when `work` settles or the bound elapses, whichever is first. */\nexport function settleWithin(work: Promise<unknown>, timeoutMs: number): Promise<void> {\n return raceTimer(work, timeoutMs, (resolve) => resolve());\n}\n","/*\n * Inspired by Akka Coordinated Shutdown: https://doc.akka.io/libraries/akka-core/current/coordinated-shutdown.html\n * and Lewis's implementation in a private repo elsewhere (https://github.com/Yomanz)\n */\n\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Logger, paint } from '@seedcord/logger';\nimport chalk from 'chalk';\n\nimport { withTimeout } from './withTimeout';\n\nimport type { LifecycleTask } from './LifecycleTypes';\n\n/**\n * Base for the startup and shutdown coordinators. Runs phase-ordered tasks off a per-phase map.\n *\n * @internal\n */\nexport abstract class CoordinatedLifecycle<TPhase extends number> {\n protected readonly logger: Logger;\n protected readonly tasksMap = new Map<TPhase, LifecycleTask[]>();\n\n protected constructor(\n loggerName: string,\n protected readonly phaseOrder: TPhase[],\n protected readonly phaseEnum: Record<number, string>\n ) {\n this.logger = new Logger(loggerName, { channel: 'lifecycle' });\n this.phaseOrder.forEach((phase) => this.tasksMap.set(phase, []));\n }\n\n /**\n * Adds a task to `phase`. Tasks run in phase order, each bounded by `timeoutMs`.\n *\n * @param phase - The lifecycle phase to add the task to\n * @param taskName - Unique name for the task, used for logging and removal\n * @param task - Async function to execute during the phase\n * @param timeoutMs - Maximum time allowed for task execution in milliseconds\n */\n public addTask(phase: TPhase, taskName: string, task: () => Promise<void>, timeoutMs: number): void {\n if (!this.canAddTask()) return;\n\n const tasks = this.tasksMap.get(phase);\n if (!tasks) {\n throw new SeedcordError(SeedcordErrorCode.LifecycleUnknownPhase, [phase]);\n }\n\n tasks.push({ name: taskName, task, timeout: timeoutMs });\n this.logger.debug(\n `${chalk.italic('Added')} ${this.getTaskType()} task ${paint.sky.bold(taskName)} to phase ${paint.iris.bold(this.phaseEnum[phase])}`\n );\n }\n\n /**\n * Removes a lifecycle task from a specific phase.\n *\n * @param phase - The lifecycle phase to remove the task from\n * @param taskName - Name of the task to remove\n * @returns True if the task was found and removed, false otherwise\n */\n public removeTask(phase: TPhase, taskName: string): boolean {\n if (!this.canRemoveTask()) return false;\n\n const tasks = this.tasksMap.get(phase);\n if (!tasks) return false;\n\n const initialLength = tasks.length;\n const filteredTasks = tasks.filter((task) => task.name !== taskName);\n this.tasksMap.set(phase, filteredTasks);\n\n const removed = initialLength !== filteredTasks.length;\n if (removed) {\n this.logger.debug(\n `${chalk.italic('Removed')} ${this.getTaskType()} task ${paint.sky.bold(taskName)} from phase ${paint.iris.bold(this.phaseEnum[phase])}`\n );\n }\n\n return removed;\n }\n\n protected async runPhase(phase: TPhase): Promise<void> {\n const tasks = this.tasksMap.get(phase) ?? [];\n if (tasks.length === 0) {\n this.logger.trace(`No tasks to run in phase ${paint.iris.bold(this.phaseEnum[phase])}`);\n return;\n }\n\n this.logger.debug(\n `${paint.amber.bold('Running')} ${this.getTaskType()} phase ${paint.iris.bold(this.phaseEnum[phase])} with ${paint.sky.bold(String(tasks.length))} tasks`\n );\n\n const results: PromiseSettledResult<void>[] = await this.executeTasksInPhase(phase, tasks);\n\n const failures = results.filter((r) => r.status === 'rejected').length;\n if (failures > 0) {\n // chalk here would leak ANSI codes into the serialized error message (the unknown-exception webhook)\n throw new SeedcordError(SeedcordErrorCode.LifecyclePhaseFailures, [this.phaseEnum[phase], failures]);\n }\n\n this.logger.debug(\n `Phase ${paint.iris.bold(this.phaseEnum[phase])} ${paint.mint.bold('completed successfully')}`\n );\n }\n\n protected async runTaskWithTimeout(phase: TPhase, task: LifecycleTask): Promise<void> {\n this.logger.trace(\n `${chalk.italic('Starting')} task ${paint.sky.bold(task.name)} in phase ${paint.iris.bold(this.phaseEnum[phase])}`\n );\n\n try {\n await withTimeout(task.name, task.task, task.timeout);\n\n this.logger.trace(\n `${chalk.italic('Completed')} task ${paint.sky.bold(task.name)} in phase ${paint.iris.bold(this.phaseEnum[phase])}`\n );\n } catch (error) {\n if (this.isAborted()) return;\n this.logger.error(\n `${chalk.italic('Failed')} task ${paint.sky.bold(task.name)} in phase ${paint.iris.bold(this.phaseEnum[phase])}:`,\n error\n );\n throw error;\n }\n }\n\n protected isAborted(): boolean {\n return false;\n }\n\n protected abstract canAddTask(): boolean;\n protected abstract canRemoveTask(): boolean;\n protected abstract getTaskType(): string;\n protected abstract executeTasksInPhase(\n phase: TPhase,\n tasks: LifecycleTask[]\n ): Promise<PromiseSettledResult<void>[]>;\n}\n","import chalk from 'chalk';\n\nimport { ShutdownPhase } from '@src/lifecycle/phases';\n\nimport { CoordinatedLifecycle } from './CoordinatedLifecycle';\n\nimport type { LifecycleTask } from './LifecycleTypes';\n\nconst PHASE_ORDER: ShutdownPhase[] = [\n ShutdownPhase.Unbind,\n ShutdownPhase.Drain,\n ShutdownPhase.Disconnect,\n ShutdownPhase.Logout\n];\n\n// gives the logger's file sink time to flush before process.exit\nconst LOG_FLUSH_DELAY_MS = 3000;\n\n/**\n * Runs registered shutdown tasks across `ShutdownPhase` in order. Registers SIGINT and SIGTERM\n * handlers. Tasks within a phase run in parallel.\n */\nexport class CoordinatedShutdown extends CoordinatedLifecycle<ShutdownPhase> {\n private isShuttingDown = false;\n private hasShutdown = false;\n private exitCode = 0;\n private onSigTerm: (() => void) | null = null;\n private onSigInt: (() => void) | null = null;\n private startupGate?: Promise<void>;\n\n public constructor() {\n super('Shutdown', PHASE_ORDER, ShutdownPhase);\n\n this.registerSignalHandlers();\n }\n\n protected canAddTask(): boolean {\n return true;\n }\n\n protected canRemoveTask(): boolean {\n return true;\n }\n\n protected getTaskType(): string {\n return 'shutdown';\n }\n\n protected async executeTasksInPhase(\n phase: ShutdownPhase,\n tasks: LifecycleTask[]\n ): Promise<PromiseSettledResult<void>[]> {\n const promises = tasks.map((task) => this.runTaskWithTimeout(phase, task));\n return Promise.allSettled(promises);\n }\n\n private registerSignalHandlers(): void {\n this.onSigTerm = () => {\n this.logger.info(`Received ${chalk.yellow.bold('SIGTERM')} signal`);\n void this.run(0);\n };\n\n this.onSigInt = () => {\n this.logger.info(`Received ${chalk.yellow.bold('SIGINT')} signal`);\n void this.run(0);\n };\n\n process.on('SIGTERM', this.onSigTerm);\n process.on('SIGINT', this.onSigInt);\n }\n\n /** @internal */\n public removeSignalHandlers(): void {\n if (this.onSigTerm) {\n process.off('SIGTERM', this.onSigTerm);\n this.onSigTerm = null;\n }\n if (this.onSigInt) {\n process.off('SIGINT', this.onSigInt);\n this.onSigInt = null;\n }\n }\n\n /** @internal run() awaits this so boot finishes registering its dispose tasks first */\n public gateOnStartup(settled: Promise<void>): void {\n this.startupGate = settled;\n }\n\n /**\n * Adds a shutdown-phase task.\n *\n * @param phase - The shutdown phase to run the task in.\n * @param taskName - A descriptive name for the task.\n * @param task - The async function to run.\n * @param timeoutMs - Task timeout in ms. {@default `5000` }\n */\n public override addTask(phase: ShutdownPhase, taskName: string, task: () => Promise<void>, timeoutMs = 5000): void {\n super.addTask(phase, taskName, task, timeoutMs);\n }\n\n /** Removes a shutdown-phase task, returning whether one was removed. */\n public override removeTask(phase: ShutdownPhase, taskName: string): boolean {\n return super.removeTask(phase, taskName);\n }\n\n /**\n * Runs registered tasks across shutdown phases in `ShutdownPhase` order.\n * Tasks within each phase run in parallel.\n *\n * @param exitCode - Process exit code. {@default `0` }\n * @param exitProcess - Whether to exit the process after shutdown. {@default `true` }\n * @example\n * ```typescript\n * shutdown.addTask(ShutdownPhase.Disconnect, 'database', () => db.disconnect(), 5000);\n * await shutdown.run(0);\n * ```\n */\n public async run(exitCode = 0, exitProcess = true): Promise<void> {\n this.removeSignalHandlers();\n\n // a dev-mode run leaves the process alive, so a second call would re-execute every task\n if (this.hasShutdown || this.isShuttingDown) {\n this.logger.warn('Shutdown sequence already ran or is in progress');\n return;\n }\n\n this.isShuttingDown = true;\n this.exitCode = exitCode;\n this.logger.info(\n `${chalk.bold.yellow('Starting')} coordinated shutdown with exit code ${chalk.bold.cyan(exitCode)}`\n );\n\n try {\n if (this.startupGate) await this.startupGate;\n const failures: unknown[] = [];\n for (const phase of PHASE_ORDER) {\n // run every phase so a mid-shutdown failure still attempts the later teardowns\n try {\n await this.runPhase(phase);\n } catch (error) {\n failures.push(error);\n }\n }\n\n if (failures.length > 0) {\n this.logger.error(`${chalk.bold.red('Coordinated shutdown failed')}`, ...failures);\n } else {\n this.logger.info(`${chalk.bold.green('Coordinated shutdown completed')} successfully`);\n }\n } finally {\n this.hasShutdown = true;\n if (exitProcess) {\n this.logger.debug(`${chalk.bold.red('Exiting')} process with code ${chalk.bold.cyan(this.exitCode)}`);\n setTimeout(() => {\n process.exit(this.exitCode);\n }, LOG_FLUSH_DELAY_MS);\n } else {\n this.logger.debug(`${chalk.bold.yellow('Skipping')} process exit (dev mode)`);\n this.isShuttingDown = false;\n }\n }\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport chalk from 'chalk';\n\nimport { StartupPhase } from '@src/lifecycle/phases';\n\nimport { CoordinatedLifecycle } from './CoordinatedLifecycle';\n\nimport type { LifecycleTask } from './LifecycleTypes';\n\nconst PHASE_ORDER: StartupPhase[] = [StartupPhase.Configuration, StartupPhase.Login, StartupPhase.Ready];\n\n/**\n * Runs registered startup tasks across `StartupPhase` in order. Tasks within a phase run in parallel.\n */\nexport class CoordinatedStartup extends CoordinatedLifecycle<StartupPhase> {\n private isStartingUp = false;\n private hasStarted = false;\n\n public constructor() {\n super('Startup', PHASE_ORDER, StartupPhase);\n }\n\n /**\n * Adds a startup-phase task.\n *\n * @param phase - The startup phase to run the task in.\n * @param taskName - A descriptive name for the task.\n * @param task - The async function to run.\n * @param timeoutMs - Task timeout in ms. {@default `10000` }\n */\n public override addTask(\n phase: StartupPhase,\n taskName: string,\n task: () => Promise<void>,\n timeoutMs = 10_000\n ): void {\n super.addTask(phase, taskName, task, timeoutMs);\n }\n\n protected canAddTask(): boolean {\n if (this.hasStarted) {\n throw new SeedcordError(SeedcordErrorCode.LifecycleAddAfterCompletion);\n }\n\n if (this.isStartingUp) {\n throw new SeedcordError(SeedcordErrorCode.LifecycleAddDuringRun);\n }\n\n return true;\n }\n\n protected canRemoveTask(): boolean {\n if (this.isStartingUp) {\n throw new SeedcordError(SeedcordErrorCode.LifecycleRemoveDuringRun);\n }\n\n return true;\n }\n\n protected getTaskType(): string {\n return 'startup';\n }\n\n protected async executeTasksInPhase(\n phase: StartupPhase,\n tasks: LifecycleTask[]\n ): Promise<PromiseSettledResult<void>[]> {\n const promises = tasks.map((task) => this.runTaskWithTimeout(phase, task));\n return Promise.allSettled(promises);\n }\n\n /**\n * Runs the registered tasks across startup phases in `StartupPhase` order. Each phase completes\n * before the next begins, and tasks within a phase run concurrently.\n *\n * @throws {@link SeedcordError} if a startup task throws.\n */\n public async run(): Promise<void> {\n if (this.hasStarted) {\n this.logger.warn('Startup sequence has already completed');\n return;\n }\n\n if (this.isStartingUp) {\n this.logger.warn('Startup sequence already in progress');\n return;\n }\n\n this.isStartingUp = true;\n this.logger.info(`${chalk.bold.green('Starting')} coordinated startup sequence`);\n\n try {\n for (const phase of PHASE_ORDER) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- abort() can flip isStartingUp to false mid-loop from the cli\n if (!this.isStartingUp) {\n this.logger.warn('Startup sequence aborted');\n return;\n }\n await this.runPhase(phase);\n }\n\n this.hasStarted = true;\n this.logger.info(`${chalk.bold.green('Coordinated startup completed')} successfully`);\n } catch (error) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- abort() can flip isStartingUp to false before this catch runs\n if (!this.isStartingUp) {\n this.logger.warn('Startup sequence aborted during error handling');\n return;\n }\n this.logger.error(`${chalk.bold.red('Coordinated startup failed')}`);\n throw error;\n } finally {\n this.isStartingUp = false;\n }\n }\n\n protected override isAborted(): boolean {\n return !this.isStartingUp;\n }\n\n /**\n * Aborts the startup sequence if it is currently running.\n */\n public abort(): void {\n if (!this.isStartingUp) return;\n\n this.isStartingUp = false;\n this.logger.warn('Aborting coordinated startup sequence');\n }\n\n public get isReady(): boolean {\n return this.hasStarted;\n }\n\n public get isRunning(): boolean {\n return this.isStartingUp;\n }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\n\nconst HTTP_OK = 200;\nconst DEFAULT_HEALTH_CHECK_PATH = '/health';\n\nexport class HealthResponder {\n public readonly path: string;\n\n constructor(path?: string) {\n this.path = path ?? DEFAULT_HEALTH_CHECK_PATH;\n }\n\n public tryRespond(req: IncomingMessage, res: ServerResponse): boolean {\n if (req.method !== 'GET' || req.url !== this.path) return false;\n\n res.writeHead(HTTP_OK, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ status: 'ok', timestamp: Date.now() }));\n return true;\n }\n}\n","import { createServer } from 'node:http';\n\nimport { Logger, paint } from '@seedcord/logger';\n\nimport { ShutdownPhase } from '@src/lifecycle/phases';\n\nimport { HealthResponder } from './HealthResponder';\n\nimport type { CoordinatedShutdown } from './Lifecycle/CoordinatedShutdown';\nimport type { HealthCheckConfig, HealthCheckOption } from '@seedcord/types';\nimport type { IncomingMessage, Server, ServerResponse } from 'node:http';\n\nconst HTTP_NOT_FOUND = 404;\n\nconst DEFAULT_HEALTH_CHECK_PORT = 6967;\n\nexport class HealthCheck {\n public readonly logger = new Logger('HealthCheck', { channel: 'health' });\n\n public readonly port: number;\n public readonly host: string | undefined;\n\n private readonly responder: HealthResponder;\n private server?: Server;\n\n constructor(shutdown: CoordinatedShutdown, options?: HealthCheckConfig) {\n this.port = options?.port ?? DEFAULT_HEALTH_CHECK_PORT;\n this.host = options?.host;\n this.responder = new HealthResponder(options?.path);\n\n shutdown.addTask(ShutdownPhase.Drain, 'stop-healthcheck-server', () => this.stop());\n }\n\n public get path(): string {\n return this.responder.path;\n }\n\n // `undefined` and `true` both build the defaults, only `false` opts out\n public static fromOption(shutdown: CoordinatedShutdown, option?: HealthCheckOption): HealthCheck | undefined {\n if (option === false) return undefined;\n return new HealthCheck(shutdown, typeof option === 'object' ? option : undefined);\n }\n\n public async init(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n if (this.responder.tryRespond(req, res)) return;\n\n res.writeHead(HTTP_NOT_FOUND, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ status: 'not found' }));\n });\n this.server = server;\n\n const onListenError = (err: Error): void => reject(err);\n server.on('error', onListenError);\n\n server.once('listening', () => {\n // a late error would reject an already-settled promise, and no 'error' listener at all crashes the process\n server.removeListener('error', onListenError);\n server.on('error', (err) => this.logger.error('Health check server error', err));\n\n // binds all interfaces, so log an address a browser can open\n const address = this.host ?? 'localhost';\n this.logger.info(\n `${paint.mint.bold('✔︎')} Health check server listening on ${paint.sky(`http://${address}:${this.port}${this.path}`)}`\n );\n resolve();\n });\n\n if (this.host) {\n this.logger.debug(`Binding health check server to ${this.host}`);\n server.listen(this.port, this.host);\n } else {\n this.logger.debug('Binding health check server to all interfaces');\n server.listen(this.port);\n }\n });\n }\n\n public stop(): Promise<void> {\n const server = this.server;\n // close() on a non-listening server invokes its callback with ERR_SERVER_NOT_RUNNING and\n // never fires 'close', so without this guard the promise would hang the shutdown phase.\n if (!server?.listening) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n // settle only in the callback, a 'close'-event resolve would swallow the callback's error\n server.close((err) => {\n if (err) {\n reject(err);\n return;\n }\n this.logger.info(paint.coral.bold('Health check server stopped'));\n resolve();\n });\n });\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { FRAMEWORK_CHANNELS, Logger } from '@seedcord/logger';\n\nimport { StartupPhase } from '@src/lifecycle/phases';\nimport { resolvedLifecycleSpecOf } from '@src/plugin/Plugin';\n\nimport { withTimeout } from './Lifecycle/withTimeout';\n\nimport type { REST } from '@discordjs/rest';\nimport type { CoreBase } from '@interfaces/CoreBase';\nimport type { CoordinatedShutdown } from '@node/Lifecycle/CoordinatedShutdown';\nimport type { CoordinatedStartup } from '@node/Lifecycle/CoordinatedStartup';\nimport type { Config, IRateLimiter } from '@seedcord/types';\nimport type { ShutdownPhase } from '@src/lifecycle/phases';\nimport type { ChannelKeyAssert, Runtime, RuntimeAssert, Transport, TransportAssert } from '@src/plugin/options';\nimport type { CoreParamAssert, PluginArgs, PluginCtor, PluginLike } from '@src/plugin/Plugin';\nimport type { Bus } from '@subscribers/Bus';\n\ninterface Attachment {\n readonly key: string;\n readonly instance: PluginLike;\n}\n\nconst RESERVED_KEYS: ReadonlySet<string> = new Set(FRAMEWORK_CHANNELS);\n\n/**\n * Base class for a plugin host, a transport `Seedcord` class.\n *\n * Plugins are attached during configuration and initialized during startup, sequentially in attach\n * order within each phase.\n */\n// no defaults, a default runtime of the full union contains 'edge' and RuntimeAssert rejects every plugin on that\nexport abstract class Pluggable<BotT extends Transport, BotRt extends Runtime> implements CoreBase {\n public abstract readonly config: Config;\n public abstract readonly rest: REST;\n public abstract readonly rateLimiter: IRateLimiter;\n public abstract readonly bus: Bus;\n\n /** @see {@link CoordinatedShutdown} */\n public readonly shutdown: CoordinatedShutdown;\n\n /** @see {@link CoordinatedStartup} */\n public readonly startup: CoordinatedStartup;\n\n protected isInitialized = false;\n protected startFailed = false;\n protected readonly plugins: PluginLike[] = [];\n\n private readonly pluginLogger = new Logger('Plugins', { channel: 'plugins' });\n\n private readonly attachments: Attachment[] = [];\n private readonly completedInits = new Set<Attachment>();\n private readonly disposePhases = new Set<ShutdownPhase>();\n private pluginTasksRegistered = false;\n\n private static isInstantiated = false;\n private static liveShutdown?: CoordinatedShutdown | undefined;\n\n constructor(shutdown: CoordinatedShutdown, startup: CoordinatedStartup) {\n if (Pluggable.isInstantiated) {\n // the caller constructed this shutdown, its signal handlers leak unless dropped here\n shutdown.removeSignalHandlers();\n throw new SeedcordError(SeedcordErrorCode.CoreSingletonViolation);\n }\n\n Pluggable.isInstantiated = true;\n Pluggable.liveShutdown = shutdown;\n this.shutdown = shutdown;\n this.startup = startup;\n }\n\n /** @internal */\n protected async init(): Promise<this> {\n if (this.isInitialized) return this;\n // a rerun after a failed startup would re-init the rolled-back plugins\n if (this.startFailed) throw new SeedcordError(SeedcordErrorCode.LifecycleRestartAfterFailure);\n\n this.registerPluginTasks();\n\n const startupSettled: PromiseWithResolvers<void> = Promise.withResolvers();\n this.shutdown.gateOnStartup(startupSettled.promise);\n\n try {\n await this.startup.run();\n } catch (caught) {\n await this.rollback();\n throw caught;\n } finally {\n startupSettled.resolve();\n }\n\n this.isInitialized = true;\n return this;\n }\n\n /** @internal codegen reads these to emit the `Core` augmentation */\n public get pluginKeys(): readonly string[] {\n return this.attachments.map((attachment) => attachment.key);\n }\n\n /** @internal so the next host can construct */\n protected static reset(): void {\n Pluggable.liveShutdown?.removeSignalHandlers();\n Pluggable.liveShutdown = undefined;\n Pluggable.isInstantiated = false;\n }\n\n /**\n * Attaches a plugin to this instance.\n *\n * The plugin initializes during startup, after every plugin attached before it, and becomes\n * available as a property on `core`. `seedcord codegen` writes the `Core` augmentation that\n * types it.\n *\n * A plugin declaring a `transport` or `runtime` this host does not run is a compile error on\n * this call. An edge host takes no plugins at all. A plugin constructor narrowing its first\n * parameter past `CoreBase` is a compile error here too. Read the transport `Core` off `this.core`.\n *\n * @typeParam Key - The property name for accessing the plugin\n * @typeParam Ctor - The plugin constructor type\n * @param key - Property name to access the plugin instance\n * @param Plugin - Plugin constructor class\n * @param args - Additional arguments to pass to the plugin constructor\n * @returns This instance with the plugin attached as a typed property\n * @throws A **SeedcordError** When called after initialization or if key already exists or is reserved\n * @example\n * ```typescript\n * seedcord.attach('db', Mongoose, { uri: 'mongodb://...', name: 'seedcord', dir: ... })\n * ```\n */\n public attach<Key extends string, Ctor extends PluginCtor>(\n this: this,\n key: ChannelKeyAssert<Key>,\n Plugin: Ctor &\n TransportAssert<InstanceType<Ctor>, BotT> &\n RuntimeAssert<InstanceType<Ctor>, BotRt> &\n CoreParamAssert<Ctor>,\n ...args: PluginArgs<Ctor>\n ): this & Record<Key, InstanceType<Ctor>> {\n if (this.isInitialized) {\n throw new SeedcordError(SeedcordErrorCode.CorePluginAfterInit);\n }\n // several reserved channels are also members on a host, which the next check would report first\n if (RESERVED_KEYS.has(key)) {\n throw new SeedcordError(SeedcordErrorCode.CorePluginReservedChannel, [key]);\n }\n if (key in this) {\n throw new SeedcordError(SeedcordErrorCode.CorePluginKeyExists, [key]);\n }\n\n const instance = new Plugin(this, ...args);\n instance.logger.setChannel(key);\n this.plugins.push(instance);\n this.attachments.push({ key, instance });\n\n return Object.assign(this, { [key]: instance } as Record<Key, InstanceType<Ctor>>);\n }\n\n // one combined task per phase keeps plugin inits sequential while the phase's other tasks run concurrently\n private registerPluginTasks(): void {\n if (this.pluginTasksRegistered) return;\n this.pluginTasksRegistered = true;\n\n const groups = new Map<StartupPhase, Attachment[]>();\n for (const attachment of this.attachments) {\n const phase = resolvedLifecycleSpecOf(attachment.instance).init.phase;\n const group = groups.get(phase) ?? [];\n group.push(attachment);\n groups.set(phase, group);\n }\n\n for (const [phase, group] of groups) {\n // Ready inits run in the combined Ready task, before the ready hooks\n if (phase === StartupPhase.Ready) continue;\n const budget = group.reduce((sum, a) => sum + resolvedLifecycleSpecOf(a.instance).init.timeout, 0);\n this.startup.addTask(phase, 'plugins-init', () => this.runInits(group), budget);\n }\n\n this.registerReadyTask(groups.get(StartupPhase.Ready) ?? []);\n }\n\n private async runInits(group: readonly Attachment[]): Promise<void> {\n for (const attachment of group) {\n const { key, instance } = attachment;\n const spec = resolvedLifecycleSpecOf(instance);\n\n instance.logger.utils.initialization(key, 'start');\n await withTimeout(`Plugin (${key})`, () => instance.init(), spec.init.timeout);\n instance.logger.utils.initialization(key, 'end');\n\n this.completedInits.add(attachment);\n if (instance.dispose) this.registerDisposeTask(spec.dispose.phase);\n }\n }\n\n private registerReadyTask(readyInits: readonly Attachment[]): void {\n const steps = this.attachments.reduce<{ key: string; run: () => Promise<void>; timeout: number }[]>(\n (acc, a) => {\n const ready = a.instance.ready?.bind(a.instance);\n if (ready) {\n acc.push({\n key: a.key,\n run: ready,\n timeout: resolvedLifecycleSpecOf(a.instance).ready.timeout\n });\n }\n return acc;\n },\n []\n );\n if (readyInits.length === 0 && steps.length === 0) return;\n\n const budget =\n readyInits.reduce((sum, a) => sum + resolvedLifecycleSpecOf(a.instance).init.timeout, 0) +\n steps.reduce((sum, step) => sum + step.timeout, 0);\n this.startup.addTask(\n StartupPhase.Ready,\n 'plugins-ready',\n async () => {\n await this.runInits(readyInits);\n for (const step of steps) {\n await withTimeout(`Plugin:${step.key}:ready`, step.run, step.timeout);\n }\n },\n budget\n );\n }\n\n private registerDisposeTask(phase: ShutdownPhase): void {\n if (this.disposePhases.has(phase)) return;\n this.disposePhases.add(phase);\n\n // registered once per phase, later inits of that phase run in the same task\n const budget = this.attachments.reduce((sum, a) => {\n const spec = resolvedLifecycleSpecOf(a.instance);\n return a.instance.dispose && spec.dispose.phase === phase ? sum + spec.dispose.timeout : sum;\n }, 0);\n this.shutdown.addTask(phase, 'plugins-dispose', () => this.runDisposals(phase), budget);\n }\n\n private async runDisposals(phase: ShutdownPhase): Promise<void> {\n const failures: unknown[] = [];\n // keep disposing the rest even when one fails\n await this.disposeCompleted(phase, (caught) => failures.push(caught));\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1) throw new AggregateError(failures, 'plugin dispose failures');\n }\n\n private async disposeCompleted(\n phase: ShutdownPhase | undefined,\n onError: (caught: unknown) => void\n ): Promise<void> {\n for (const attachment of [...this.attachments].reverse()) {\n if (!this.completedInits.has(attachment)) continue;\n const dispose = attachment.instance.dispose?.bind(attachment.instance);\n if (!dispose) continue;\n const spec = resolvedLifecycleSpecOf(attachment.instance);\n if (phase !== undefined && spec.dispose.phase !== phase) continue;\n\n try {\n await withTimeout(`Plugin:${attachment.key}:dispose`, dispose, spec.dispose.timeout);\n } catch (caught) {\n onError(caught);\n }\n }\n }\n\n private async rollback(): Promise<void> {\n this.startFailed = true;\n // log rollback dispose failures so they do not hide the startup error\n await this.disposeCompleted(undefined, (caught) => this.pluginLogger.warn('rollback dispose failed', caught));\n // prevents re-dispose when shutdown runs after rollback\n this.completedInits.clear();\n }\n}\n","import { traverseDirectory } from '@seedcord/utils/node';\nimport chalk from 'chalk';\nimport { Envapter } from 'envapt';\n\nimport { HmrModuleHandler } from '@hmr/HmrModuleHandler';\nimport { SubscribeMetadataKey } from '@src/metadataKeys';\nimport { registrationFor, Subscriber } from '@subscribers/index';\n\nimport type { HmrAware, HmrUpdateEvent } from '@seedcord/types';\nimport type { Initializeable } from '@src/plugin/Plugin';\nimport type { SubscribeMetadataEntry } from '@subscribers/decorators/Subscribe';\nimport type { StoredSubscriberCtor, Bus } from '@subscribers/index';\nimport type { SubscriptionKey } from '@subscribers/types/Subscriptions';\n\ntype SubscriberArtifact = SubscriptionKey[];\n\n/**\n * Loads subscribers off the filesystem into a {@link Bus} and stores their hot-reload wiring. Node\n * only, a bundled isolate registers from the manifest instead.\n *\n * @internal\n */\nexport class SubscriberLoader implements Initializeable, HmrAware {\n private isInitialized = false;\n private readonly hmrHandler?: HmrModuleHandler<StoredSubscriberCtor, void, SubscriberArtifact>;\n\n constructor(\n private readonly bus: Bus,\n private readonly directory: string | null\n ) {\n if (!this.directory) return;\n if (!Envapter.isDevelopment && !Envapter.isTest) return;\n\n this.hmrHandler = new HmrModuleHandler({\n handlersDir: this.directory,\n isHandler: this.isSubscriber.bind(this),\n registerHandler: this.registerSubscriber.bind(this),\n unregisterHandler: this.unregisterSubscriber.bind(this),\n getArtifacts: this.getArtifacts.bind(this),\n logger: this.bus.logger\n });\n }\n\n /** @internal */\n public async init(): Promise<void> {\n if (this.isInitialized) return;\n this.isInitialized = true;\n\n this.bus.registerDefaults();\n\n const { directory } = this;\n if (directory) {\n this.bus.logger.debug(chalk.bold(directory));\n await this.load(directory);\n this.bus.logger.utils.list(\n [`${chalk.bold.magenta(this.bus.registeredCount)} subscribers`],\n chalk.bold.green('Loaded'),\n 'debug'\n );\n }\n\n if (!Envapter.isTest) await this.bus.verifyWebhooks();\n }\n\n /** @internal */\n public async onHmr(event: HmrUpdateEvent): Promise<void> {\n if (this.hmrHandler) await this.hmrHandler.handle(event);\n }\n\n private async load(dir: string): Promise<void> {\n await traverseDirectory(dir, (fullPath, relativePath, imported) => {\n for (const exportName of Object.keys(imported)) {\n const value = imported[exportName];\n if (!this.isSubscriber(value)) continue;\n\n this.registerSubscriber(value);\n this.hmrHandler?.trackHandler(fullPath, value);\n this.bus.logger.utils.registration(value.name, relativePath, undefined, 'trace');\n }\n });\n }\n\n private registerSubscriber(ctor: StoredSubscriberCtor): void {\n this.bus.register(registrationFor(ctor));\n }\n\n private unregisterSubscriber(ctor: StoredSubscriberCtor, artifacts?: SubscriberArtifact): void {\n this.bus.unregister(ctor, artifacts);\n }\n\n private getArtifacts(ctor: StoredSubscriberCtor): SubscriberArtifact {\n const meta = Reflect.getMetadata(SubscribeMetadataKey, ctor) as SubscribeMetadataEntry;\n return [meta.subscriber];\n }\n\n private isSubscriber(value: unknown): value is StoredSubscriberCtor {\n if (typeof value !== 'function') return false;\n return value.prototype instanceof Subscriber && Reflect.hasMetadata(SubscribeMetadataKey, value);\n }\n}\n","import { resolve } from 'node:path';\n\nimport { SlashCommandBuilder } from '@discordjs/builders';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Logger, paint } from '@seedcord/logger';\nimport { formatFilePath } from '@seedcord/utils';\nimport { traverseDirectory } from '@seedcord/utils/node';\nimport chalk from 'chalk';\nimport { Routes } from 'discord-api-types/v10';\nimport { Envapter } from 'envapt';\n\nimport { BuilderComponent } from '@components/Component';\nimport { getDevChannel } from '@hmr/devChannel';\nimport { HmrModuleHandler } from '@hmr/HmrModuleHandler';\nimport { contextMenuLeaves } from '@src/commands/contextMenuLeaves';\nimport { slashRouteLeaves } from '@src/commands/slashRouteLeaves';\nimport { CommandMetadataKey } from '@src/metadataKeys';\n\nimport type { CommandMeta } from '@decorators/Command';\nimport type { REST } from '@discordjs/rest';\nimport type { HmrAware, HmrUpdateEvent } from '@seedcord/types';\nimport type { ContextMenuLeaves } from '@src/commands/contextMenuLeaves';\nimport type { CommandBuilder, DeployResult } from '@src/commands/types';\nimport type { Initializeable } from '@src/plugin/Plugin';\nimport type { APIApplicationCommand } from 'discord-api-types/v10';\n\ntype CommandCtor = new () => BuilderComponent<'command' | 'context_menu'>;\n\n/** @internal */\nexport interface CommandRegistryOptions {\n readonly dir: string;\n readonly rest: REST;\n /** Called at deploy time, because the application id only resolves after login. */\n readonly applicationId: () => string;\n readonly onDeployed?: (result: DeployResult) => void;\n}\n\ninterface CommandArtifact {\n name: string;\n scope: 'global' | 'guild';\n guilds?: string[];\n}\n\nfunction indexById(commands: readonly APIApplicationCommand[]): Map<string, APIApplicationCommand> {\n return new Map(commands.map((command) => [command.id, command]));\n}\n\n/**\n * Scans the command directory, builds each command, and PUTs the global and guild scopes to Discord.\n *\n * @internal\n */\nexport class CommandRegistry implements Initializeable, HmrAware {\n private readonly logger = new Logger('Commands', { channel: 'commands' });\n private isInitialised = false;\n\n public readonly globalCommands: CommandBuilder[] = [];\n public readonly guildCommands = new Map<string, CommandBuilder[]>();\n\n private readonly ctorToCommand = new Map<CommandCtor, CommandArtifact>();\n\n // batched during bulk load. A reload reports on the hmr channel instead\n private loading = false;\n private readonly loadedCommands: { name: string; from: string; kind: 'slash command' | 'context menu' }[] = [];\n\n private readonly hmrHandler?: HmrModuleHandler<CommandCtor, void, CommandArtifact | undefined>;\n private readonly pendingEvents = new Map<string, HmrUpdateEvent>();\n\n public constructor(private readonly options: CommandRegistryOptions) {\n if (!options.dir) {\n throw new SeedcordError(SeedcordErrorCode.CoreControllerPathMissing, ['CommandRegistry', 'commands']);\n }\n\n if (!Envapter.isDevelopment && !Envapter.isTest) return;\n this.hmrHandler = new HmrModuleHandler<CommandCtor, void, CommandArtifact | undefined>({\n handlersDir: options.dir,\n isHandler: this.isCommandClass.bind(this),\n registerHandler: this.registerCommand.bind(this),\n unregisterHandler: this.unregisterCommand.bind(this),\n getArtifacts: this.getArtifacts.bind(this),\n logger: this.logger\n });\n }\n\n private getArtifacts(ctor: CommandCtor): CommandArtifact | undefined {\n return this.ctorToCommand.get(ctor);\n }\n\n /** @internal */\n public async init(): Promise<void> {\n if (this.isInitialised) return;\n this.isInitialised = true;\n\n this.loading = true;\n this.loadedCommands.length = 0;\n try {\n await this.loadCommands(this.options.dir);\n } finally {\n this.loading = false;\n }\n\n this.reportLoad();\n\n getDevChannel()?.on('seedcord:refresh-commands', (data) => {\n void this.refresh(data.shouldRefresh);\n });\n }\n\n private reportLoad(): void {\n const { utils } = this.logger;\n\n utils.summary(\n 'Loaded commands',\n { global: this.globalCommands.length, 'guild groups': this.guildCommands.size },\n 'debug'\n );\n\n let slash = 0;\n let menu = 0;\n for (const command of this.loadedCommands) {\n if (command.kind === 'slash command') slash++;\n else menu++;\n }\n\n utils.block(\n 'Loaded commands',\n [\n ...utils.entries(this.loadedCommands),\n ...utils.counts({ 'slash commands': slash, 'context menus': menu })\n ],\n 'debug'\n );\n }\n\n /** @internal */\n public async refresh(shouldRefresh = true): Promise<void> {\n if (!shouldRefresh) {\n this.logger.debug(chalk.italic('Command refresh cancelled.'));\n this.pendingEvents.clear();\n return;\n }\n\n this.logger.debug(chalk.italic('Refreshing commands...'));\n for (const event of this.pendingEvents.values()) {\n await this.hmrHandler?.handle(event);\n }\n this.pendingEvents.clear();\n await this.setCommands();\n }\n\n /** @internal */\n public async onHmr(event: HmrUpdateEvent): Promise<void> {\n if (event.file.startsWith(resolve(process.cwd(), this.options.dir))) {\n this.pendingEvents.delete(event.file);\n this.pendingEvents.set(event.file, event);\n getDevChannel()?.send('seedcord:commands-update-prompt', {\n files: [...this.pendingEvents.keys()].map((f) => formatFilePath(f))\n });\n } else {\n await this.hmrHandler?.handle(event);\n }\n }\n\n private async loadCommands(dir: string): Promise<void> {\n await traverseDirectory(dir, (fullPath, rel, mod) => {\n for (const exported of Object.values(mod))\n if (this.isCommandClass(exported)) {\n this.registerCommand(exported, rel);\n this.hmrHandler?.trackHandler(fullPath, exported);\n }\n });\n }\n\n private isCommandClass(obj: unknown): obj is CommandCtor {\n if (typeof obj !== 'function') return false;\n return obj.prototype instanceof BuilderComponent && Reflect.hasMetadata(CommandMetadataKey, obj);\n }\n\n private registerCommand(ctor: CommandCtor, rel: string): void {\n const meta = Reflect.getMetadata(CommandMetadataKey, ctor) as CommandMeta | undefined;\n\n if (!meta) return;\n\n const instance = new ctor();\n const comp = instance.component;\n const kind = comp instanceof SlashCommandBuilder ? 'slash command' : 'context menu';\n\n if (meta.scope === 'global') {\n this.globalCommands.push(comp);\n } else {\n for (const g of meta.guilds) {\n const arr = this.guildCommands.get(g) ?? [];\n arr.push(comp);\n this.guildCommands.set(g, arr);\n }\n }\n\n this.ctorToCommand.set(ctor, {\n name: comp.name,\n scope: meta.scope,\n ...(meta.scope === 'guild' && { guilds: meta.guilds })\n });\n\n if (this.loading) {\n this.loadedCommands.push({ name: comp.name, from: formatFilePath(rel), kind });\n }\n }\n\n private unregisterCommand(ctor: CommandCtor, artifacts?: CommandArtifact): void {\n const info = artifacts ?? this.ctorToCommand.get(ctor);\n if (!info) return;\n\n if (info.scope === 'global') {\n const idx = this.globalCommands.findIndex((c) => c.name === info.name);\n if (idx !== -1) this.globalCommands.splice(idx, 1);\n } else {\n for (const g of info.guilds ?? []) {\n const arr = this.guildCommands.get(g);\n if (arr) {\n const idx = arr.findIndex((c) => c.name === info.name);\n if (idx !== -1) arr.splice(idx, 1);\n }\n }\n }\n this.ctorToCommand.delete(ctor);\n }\n\n /** @internal */\n public async setCommands(): Promise<DeployResult> {\n const result: DeployResult = { global: new Map(), guilds: new Map() };\n const appId = this.options.applicationId();\n\n if (this.globalCommands.length > 0) {\n const deployed = await this.put(Routes.applicationCommands(appId), this.globalCommands);\n result.global = indexById(deployed);\n const tag = this.globalCommands.length === 1 ? 'command' : 'commands';\n this.logger.utils.block(\n `Deployed ${this.globalCommands.length} global ${tag}`,\n this.logger.utils.wrap(this.globalCommands.map((command) => command.name)),\n 'info'\n );\n }\n\n for (const [guildId, commands] of this.guildCommands.entries()) {\n const deployed = await this.put(Routes.applicationGuildCommands(appId, guildId), commands);\n result.guilds.set(guildId, indexById(deployed));\n const tag = commands.length === 1 ? 'command' : 'commands';\n this.logger.utils.block(\n `Deployed ${commands.length} ${tag} to ${paint.amber.bold(guildId)}`,\n this.logger.utils.wrap(commands.map((command) => command.name)),\n 'info'\n );\n }\n\n this.options.onDeployed?.(result);\n return result;\n }\n\n private async put(route: `/${string}`, commands: readonly CommandBuilder[]): Promise<APIApplicationCommand[]> {\n const body = commands.map((command) => command.toJSON());\n // justified: the bulk-overwrite routes return the deployed command array\n return (await this.options.rest.put(route, { body })) as APIApplicationCommand[];\n }\n\n /** Every registered builder, global first. A guild command in N guilds appears once per guild. @internal */\n public allCommands(): CommandBuilder[] {\n return [...this.globalCommands, ...this.guildCommands.values()].flat();\n }\n\n /** @internal */\n public routeLeaves(): Set<string> {\n return slashRouteLeaves(this.allCommands());\n }\n\n /** @internal */\n public contextMenuLeaves(): ContextMenuLeaves {\n return contextMenuLeaves(this.allCommands());\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,3 @@
1
-
2
1
  //#region src/lifecycle/phases.ts
3
2
  /**
4
3
  * Startup phases, in run order.
@@ -40,4 +39,4 @@ Object.defineProperty(exports, 'StartupPhase', {
40
39
  return StartupPhase;
41
40
  }
42
41
  });
43
- //# sourceMappingURL=phases-DcuDHoQl.cjs.map
42
+ //# sourceMappingURL=phases-8qiiLKjS.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"phases-DcuDHoQl.cjs","names":[],"sources":["../src/lifecycle/phases.ts"],"sourcesContent":["/**\n * Startup phases, in run order.\n */\nexport enum StartupPhase {\n /** Nothing connected. Plugin init runs here by default. */\n Configuration = 1,\n /** The gateway session opens, and http runs its REST-only startup work. */\n Login,\n /** Handlers are live and interactions dispatch. */\n Ready\n}\n\n/**\n * Shutdown phases, in run order.\n */\nexport enum ShutdownPhase {\n /** Stop taking new interactions and requests. */\n Unbind = 1,\n /** Waits for in-flight work to settle and stops internal services. */\n Drain,\n /** External resources close. Plugin dispose runs here by default. */\n Disconnect,\n /** The client disconnects last so in-flight handlers can still reference it during drain. */\n Logout\n}\n"],"mappings":";;;;;AAGA,IAAY,eAAL;;CAEH;;CAEA;;CAEA;;AACJ;;;;AAKA,IAAY,gBAAL;;CAEH;;CAEA;;CAEA;;CAEA;;AACJ"}
1
+ {"version":3,"file":"phases-8qiiLKjS.cjs","names":[],"sources":["../src/lifecycle/phases.ts"],"sourcesContent":["/**\n * Startup phases, in run order.\n */\nexport enum StartupPhase {\n /** Nothing connected. Plugin init runs here by default. */\n Configuration = 1,\n /** The gateway session opens, and http runs its REST-only startup work. */\n Login,\n /** Handlers are live and interactions dispatch. */\n Ready\n}\n\n/**\n * Shutdown phases, in run order.\n */\nexport enum ShutdownPhase {\n /** Stop taking new interactions and requests. */\n Unbind = 1,\n /** Waits for in-flight work to settle and stops internal services. */\n Drain,\n /** External resources close. Plugin dispose runs here by default. */\n Disconnect,\n /** The client disconnects last so in-flight handlers can still reference it during drain. */\n Logout\n}\n"],"mappings":";;;;AAGA,IAAY,eAAL;;CAEH;;CAEA;;CAEA;;AACJ;;;;AAKA,IAAY,gBAAL;;CAEH;;CAEA;;CAEA;;CAEA;;AACJ"}
@@ -1,4 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_Plugin = require('./Plugin-BlkhHNRm.cjs');
2
+ const require_Plugin = require('./Plugin-DVNh1kvX.cjs');
3
3
 
4
4
  exports.Plugin = require_Plugin.Plugin;
@@ -1,3 +1,3 @@
1
- import { c as PluginOptions, n as Initializeable, p as PluginLifecycleSpec, r as Plugin } from "./Plugin-BZit5HUI.mjs";
1
+ import { c as PluginOptions, n as Initializeable, p as PluginLifecycleSpec, r as Plugin } from "./Plugin-BPz0obbN.mjs";
2
2
  import { HmrAware, HmrUpdateEvent } from "@seedcord/types";
3
3
  export { type HmrAware, type HmrUpdateEvent, type Initializeable, Plugin, type PluginLifecycleSpec, type PluginOptions };