@seedcord/core 0.3.0 → 0.4.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 (39) hide show
  1. package/dist/{Bus-DcuUtOEL.mjs → Bus-BVwmKc-A.mjs} +51 -17
  2. package/dist/Bus-BVwmKc-A.mjs.map +1 -0
  3. package/dist/Pluggable-Cf5-WWmW.mjs +280 -0
  4. package/dist/Pluggable-Cf5-WWmW.mjs.map +1 -0
  5. package/dist/Pluggable-DFNUIlJM.d.mts +148 -0
  6. package/dist/{Plugin-Bkeqcjy6.mjs → Plugin-C6oMqWf8.mjs} +32 -7
  7. package/dist/Plugin-C6oMqWf8.mjs.map +1 -0
  8. package/dist/Plugin-CG9pWbPF.d.mts +193 -0
  9. package/dist/{cursor-DKKKUa_7.d.mts → cursor-BcRfmTSo.d.mts} +27 -140
  10. package/dist/{cursor-Cv1Ui6gZ.mjs → cursor-GBUYz3jk.mjs} +377 -176
  11. package/dist/cursor-GBUYz3jk.mjs.map +1 -0
  12. package/dist/{index-uBwh8r7x.d.mts → index-ZzdQafFv.d.mts} +2 -2
  13. package/dist/index.d.mts +132 -19
  14. package/dist/index.mjs +186 -19
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/internal.index.d.mts +11 -4
  17. package/dist/internal.index.mjs +8 -455
  18. package/dist/internal.index.mjs.map +1 -1
  19. package/dist/node-internal.index.d.mts +10 -146
  20. package/dist/node-internal.index.mjs +43 -470
  21. package/dist/node-internal.index.mjs.map +1 -1
  22. package/dist/node.index.d.mts +2 -0
  23. package/dist/node.index.mjs +256 -0
  24. package/dist/node.index.mjs.map +1 -0
  25. package/dist/{Plugin-B6iRzm3g.d.mts → phases-F8yvPd60.d.mts} +111 -207
  26. package/dist/plugin.index.d.mts +2 -2
  27. package/dist/plugin.index.mjs +1 -1
  28. package/dist/publishDefault-D826XXDQ.mjs +14 -0
  29. package/dist/publishDefault-D826XXDQ.mjs.map +1 -0
  30. package/dist/{slashRouteLeaves-De1SxqnX.mjs → slashRouteLeaves-CbYRwqMY.mjs} +10 -2
  31. package/dist/slashRouteLeaves-CbYRwqMY.mjs.map +1 -0
  32. package/dist/subscribers-CGGQkUfM.mjs +139 -0
  33. package/dist/subscribers-CGGQkUfM.mjs.map +1 -0
  34. package/package.json +14 -8
  35. package/dist/Bus-DcuUtOEL.mjs.map +0 -1
  36. package/dist/Plugin-Bkeqcjy6.mjs.map +0 -1
  37. package/dist/cursor-Cv1Ui6gZ.mjs.map +0 -1
  38. package/dist/slashRouteLeaves-De1SxqnX.mjs.map +0 -1
  39. package/dist/subscribers-DuHg-bGT.mjs +0 -3
@@ -1,284 +1,22 @@
1
- import { S as SubscribeMetadataKey, c as Subscriber, f as BuilderComponent, h as CommandMetadataKey, n as busLoggerOf, r as registrationFor, w as contextMenuLeaves } from "./Bus-DcuUtOEL.mjs";
1
+ import { D as SubscribeMetadataKey, M as contextMenuLeaves, a as RegisterSubscriber, b as CommandMetadataKey, c as VerifyWebhooks, f as Subscriber, i as RegisterDefaults, n as busLoggerOf, o as RegisteredCount, r as registrationFor, s as UnregisterSubscriber } from "./Bus-BVwmKc-A.mjs";
2
+ import { t as CommandInjector } from "./subscribers-CGGQkUfM.mjs";
3
+ import { t as PublishDefault } from "./publishDefault-D826XXDQ.mjs";
2
4
  import { n as StartupPhase, t as ShutdownPhase } from "./phases-BauKJOTT.mjs";
3
- import "./subscribers-DuHg-bGT.mjs";
4
5
  import { t as getDevChannel } from "./devChannel-CQU7hq7Q.mjs";
5
- import { n as pluginLoggerOf, r as resolvedLifecycleSpecOf } from "./Plugin-Bkeqcjy6.mjs";
6
- import { t as slashRouteLeaves } from "./slashRouteLeaves-De1SxqnX.mjs";
6
+ import { n as isCommandClass, t as slashRouteLeaves } from "./slashRouteLeaves-CbYRwqMY.mjs";
7
7
  import { t as HmrModuleHandler } from "./HmrModuleHandler-9AUfKXRl.mjs";
8
+ import { i as settleWithin, n as shutdownOf, r as assertNodeVersion } from "./Pluggable-Cf5-WWmW.mjs";
8
9
  import { SlashCommandBuilder } from "@discordjs/builders";
9
10
  import { SeedcordErrorCode, paint } from "@seedcord/errors";
10
- import { FRAMEWORK_CHANNELS, Logger } from "@seedcord/logger";
11
+ import { Logger } from "@seedcord/logger";
11
12
  import { Routes } from "discord-api-types/v10";
12
- import { SeedcordAggregateError, SeedcordError } from "@seedcord/errors/internal";
13
+ import { SeedcordError } from "@seedcord/errors/internal";
13
14
  import { formatFilePath } from "@seedcord/utils";
14
15
  import { Envapter } from "envapt";
15
16
  import { resolve } from "node:path";
16
17
  import { createServer } from "node:http";
17
18
  import { traverseDirectory } from "@seedcord/utils/node";
18
19
 
19
- //#region src/node/Lifecycle/withTimeout.ts
20
- async function raceTimer(work, timeoutMs, onTimeout) {
21
- let timer;
22
- try {
23
- await Promise.race([work, new Promise((resolve, reject) => {
24
- timer = setTimeout(() => onTimeout(resolve, reject), timeoutMs);
25
- })]);
26
- } finally {
27
- if (timer) clearTimeout(timer);
28
- }
29
- }
30
- function withTimeout(name, run, timeoutMs) {
31
- return raceTimer(run(), timeoutMs, (_, reject) => {
32
- reject(new SeedcordError(SeedcordErrorCode.LifecycleTaskTimeout, [name, timeoutMs]));
33
- });
34
- }
35
- function settleWithin(work, timeoutMs) {
36
- return raceTimer(work, timeoutMs, (resolve) => resolve());
37
- }
38
-
39
- //#endregion
40
- //#region src/node/Lifecycle/CoordinatedLifecycle.ts
41
- var CoordinatedLifecycle = class {
42
- phaseOrder;
43
- phaseEnum;
44
- logger;
45
- tasksMap = /* @__PURE__ */ new Map();
46
- constructor(loggerName, phaseOrder, phaseEnum) {
47
- this.phaseOrder = phaseOrder;
48
- this.phaseEnum = phaseEnum;
49
- this.logger = new Logger(loggerName, { channel: "lifecycle" });
50
- this.phaseOrder.forEach((phase) => this.tasksMap.set(phase, []));
51
- }
52
- addTask(phase, taskName, task, timeoutMs) {
53
- if (!this.canAddTask()) return;
54
- const tasks = this.tasksMap.get(phase);
55
- if (!tasks) throw new SeedcordError(SeedcordErrorCode.LifecycleUnknownPhase, [phase]);
56
- tasks.push({
57
- name: taskName,
58
- task,
59
- timeout: timeoutMs
60
- });
61
- this.logger.debug(`${paint.italic("Added")} ${this.getTaskType()} task ${paint.sky.bold(taskName)} to phase ${paint.iris.bold(this.phaseEnum[phase])}`);
62
- }
63
- removeTask(phase, taskName) {
64
- if (!this.canRemoveTask()) return false;
65
- const tasks = this.tasksMap.get(phase);
66
- if (!tasks) return false;
67
- const initialLength = tasks.length;
68
- const filteredTasks = tasks.filter((task) => task.name !== taskName);
69
- this.tasksMap.set(phase, filteredTasks);
70
- const removed = initialLength !== filteredTasks.length;
71
- if (removed) this.logger.debug(`${paint.italic("Removed")} ${this.getTaskType()} task ${paint.sky.bold(taskName)} from phase ${paint.iris.bold(this.phaseEnum[phase])}`);
72
- return removed;
73
- }
74
- async runPhase(phase) {
75
- const tasks = this.tasksMap.get(phase) ?? [];
76
- if (tasks.length === 0) {
77
- this.logger.trace(`No tasks to run in phase ${paint.iris.bold(this.phaseEnum[phase])}`);
78
- return;
79
- }
80
- this.logger.debug(`${paint.amber.bold("Running")} ${this.getTaskType()} phase ${paint.iris.bold(this.phaseEnum[phase])} with ${paint.sky.bold(String(tasks.length))} tasks`);
81
- const reasons = (await this.executeTasksInPhase(phase, tasks)).reduce((rejected, result) => {
82
- if (result.status === "rejected") rejected.push(result.reason);
83
- return rejected;
84
- }, []);
85
- if (reasons.length > 0) throw new SeedcordAggregateError(SeedcordErrorCode.LifecyclePhaseFailures, reasons, [this.phaseEnum[phase], reasons.length]);
86
- this.logger.debug(`Phase ${paint.iris.bold(this.phaseEnum[phase])} ${paint.mint.bold("completed successfully")}`);
87
- }
88
- async runTaskWithTimeout(phase, task) {
89
- this.logger.trace(`${paint.italic("Starting")} task ${paint.sky.bold(task.name)} in phase ${paint.iris.bold(this.phaseEnum[phase])}`);
90
- try {
91
- await withTimeout(task.name, task.task, task.timeout);
92
- this.logger.trace(`${paint.italic("Completed")} task ${paint.sky.bold(task.name)} in phase ${paint.iris.bold(this.phaseEnum[phase])}`);
93
- } catch (error) {
94
- if (this.isAborted()) return;
95
- this.logger.error(`${paint.italic("Failed")} task ${paint.sky.bold(task.name)} in phase ${paint.iris.bold(this.phaseEnum[phase])}:`, error);
96
- throw error;
97
- }
98
- }
99
- isAborted() {
100
- return false;
101
- }
102
- };
103
-
104
- //#endregion
105
- //#region src/node/Lifecycle/CoordinatedShutdown.ts
106
- const PHASE_ORDER$1 = [
107
- 1,
108
- 2,
109
- 3,
110
- 4
111
- ];
112
- const LOG_FLUSH_DELAY_MS = 3e3;
113
- var CoordinatedShutdown = class extends CoordinatedLifecycle {
114
- isShuttingDown = false;
115
- hasShutdown = false;
116
- exitCode = 0;
117
- onSigTerm = null;
118
- onSigInt = null;
119
- startupGate;
120
- constructor() {
121
- super("Shutdown", PHASE_ORDER$1, ShutdownPhase);
122
- this.registerSignalHandlers();
123
- }
124
- canAddTask() {
125
- return true;
126
- }
127
- canRemoveTask() {
128
- return true;
129
- }
130
- getTaskType() {
131
- return "shutdown";
132
- }
133
- async executeTasksInPhase(phase, tasks) {
134
- const promises = tasks.map((task) => this.runTaskWithTimeout(phase, task));
135
- return Promise.allSettled(promises);
136
- }
137
- registerSignalHandlers() {
138
- this.onSigTerm = () => {
139
- this.logger.info(`Received ${paint.amber.bold("SIGTERM")} signal`);
140
- this.run(0);
141
- };
142
- this.onSigInt = () => {
143
- this.logger.info(`Received ${paint.amber.bold("SIGINT")} signal`);
144
- this.run(0);
145
- };
146
- process.on("SIGTERM", this.onSigTerm);
147
- process.on("SIGINT", this.onSigInt);
148
- }
149
- /** @internal */
150
- removeSignalHandlers() {
151
- if (this.onSigTerm) {
152
- process.off("SIGTERM", this.onSigTerm);
153
- this.onSigTerm = null;
154
- }
155
- if (this.onSigInt) {
156
- process.off("SIGINT", this.onSigInt);
157
- this.onSigInt = null;
158
- }
159
- }
160
- /** @internal run() awaits this so boot finishes registering its dispose tasks first */
161
- gateOnStartup(settled) {
162
- this.startupGate = settled;
163
- }
164
- addTask(phase, taskName, task, timeoutMs = 5e3) {
165
- super.addTask(phase, taskName, task, timeoutMs);
166
- }
167
- removeTask(phase, taskName) {
168
- return super.removeTask(phase, taskName);
169
- }
170
- async run(exitCode = 0, exitProcess = true) {
171
- this.removeSignalHandlers();
172
- if (this.hasShutdown || this.isShuttingDown) {
173
- this.logger.warn("Shutdown sequence already ran or is in progress");
174
- return;
175
- }
176
- this.isShuttingDown = true;
177
- this.exitCode = exitCode;
178
- this.logger.info(`${paint.amber.bold("Starting")} coordinated shutdown with exit code ${paint.sky.bold(exitCode)}`);
179
- try {
180
- if (this.startupGate) await this.startupGate;
181
- const failures = [];
182
- for (const phase of PHASE_ORDER$1) try {
183
- await this.runPhase(phase);
184
- } catch (error) {
185
- failures.push(error);
186
- }
187
- if (failures.length > 0) this.logger.error(`${paint.coral.bold("Coordinated shutdown failed")}`, ...failures);
188
- else this.logger.info(`${paint.mint.bold("Coordinated shutdown completed")} successfully`);
189
- } finally {
190
- this.hasShutdown = true;
191
- if (exitProcess) {
192
- this.logger.debug(`${paint.coral.bold("Exiting")} process with code ${paint.sky.bold(this.exitCode)}`);
193
- setTimeout(() => {
194
- process.exit(this.exitCode);
195
- }, LOG_FLUSH_DELAY_MS);
196
- } else {
197
- this.logger.debug(`${paint.amber.bold("Skipping")} process exit (dev mode)`);
198
- this.isShuttingDown = false;
199
- }
200
- }
201
- }
202
- };
203
-
204
- //#endregion
205
- //#region src/node/Lifecycle/CoordinatedStartup.ts
206
- const PHASE_ORDER = [
207
- 1,
208
- 2,
209
- 3
210
- ];
211
- var CoordinatedStartup = class extends CoordinatedLifecycle {
212
- isStartingUp = false;
213
- hasStarted = false;
214
- constructor() {
215
- super("Startup", PHASE_ORDER, StartupPhase);
216
- }
217
- addTask(phase, taskName, task, timeoutMs = 1e4) {
218
- super.addTask(phase, taskName, task, timeoutMs);
219
- }
220
- canAddTask() {
221
- if (this.hasStarted) throw new SeedcordError(SeedcordErrorCode.LifecycleAddAfterCompletion);
222
- if (this.isStartingUp) throw new SeedcordError(SeedcordErrorCode.LifecycleAddDuringRun);
223
- return true;
224
- }
225
- canRemoveTask() {
226
- if (this.isStartingUp) throw new SeedcordError(SeedcordErrorCode.LifecycleRemoveDuringRun);
227
- return true;
228
- }
229
- getTaskType() {
230
- return "startup";
231
- }
232
- async executeTasksInPhase(phase, tasks) {
233
- const promises = tasks.map((task) => this.runTaskWithTimeout(phase, task));
234
- return Promise.allSettled(promises);
235
- }
236
- async run() {
237
- if (this.hasStarted) {
238
- this.logger.warn("Startup sequence has already completed");
239
- return;
240
- }
241
- if (this.isStartingUp) {
242
- this.logger.warn("Startup sequence already in progress");
243
- return;
244
- }
245
- this.isStartingUp = true;
246
- this.logger.info(`${paint.mint.bold("Starting")} coordinated startup sequence`);
247
- try {
248
- for (const phase of PHASE_ORDER) {
249
- if (!this.isStartingUp) {
250
- this.logger.warn("Startup sequence aborted");
251
- return;
252
- }
253
- await this.runPhase(phase);
254
- }
255
- this.hasStarted = true;
256
- this.logger.info(`${paint.mint.bold("Coordinated startup completed")} successfully`);
257
- } catch (error) {
258
- if (!this.isStartingUp) {
259
- this.logger.warn("Startup sequence aborted during error handling");
260
- return;
261
- }
262
- this.logger.error(`${paint.coral.bold("Coordinated startup failed")}`);
263
- throw error;
264
- } finally {
265
- this.isStartingUp = false;
266
- }
267
- }
268
- isAborted() {
269
- return !this.isStartingUp;
270
- }
271
- abort() {
272
- if (!this.isStartingUp) return;
273
- this.isStartingUp = false;
274
- this.logger.warn("Aborting coordinated startup sequence");
275
- }
276
- get isReady() {
277
- return this.hasStarted;
278
- }
279
- };
280
-
281
- //#endregion
282
20
  //#region src/node/HealthResponder.ts
283
21
  const HTTP_OK = 200;
284
22
  const DEFAULT_HEALTH_CHECK_PATH = "/health";
@@ -369,185 +107,6 @@ var HealthCheck = class HealthCheck {
369
107
  }
370
108
  };
371
109
 
372
- //#endregion
373
- //#region src/node/Pluggable.ts
374
- const RESERVED_KEYS = new Set(FRAMEWORK_CHANNELS);
375
- /**
376
- * Base class for a plugin host, a transport `Seedcord` class.
377
- *
378
- * Plugins are attached during configuration and initialized during startup, sequentially in attach
379
- * order within each phase.
380
- */
381
- var Pluggable = class Pluggable {
382
- /** @see {@link CoordinatedShutdown} */
383
- shutdown;
384
- /** @see {@link CoordinatedStartup} */
385
- startup;
386
- isInitialized = false;
387
- startFailed = false;
388
- plugins = [];
389
- pluginLogger = new Logger("Plugins", { channel: "plugins" });
390
- attachments = [];
391
- completedInits = /* @__PURE__ */ new Set();
392
- disposePhases = /* @__PURE__ */ new Set();
393
- pluginTasksRegistered = false;
394
- static isInstantiated = false;
395
- static liveShutdown;
396
- constructor(shutdown, startup) {
397
- if (Pluggable.isInstantiated) {
398
- shutdown.removeSignalHandlers();
399
- throw new SeedcordError(SeedcordErrorCode.CoreSingletonViolation);
400
- }
401
- Pluggable.isInstantiated = true;
402
- Pluggable.liveShutdown = shutdown;
403
- this.shutdown = shutdown;
404
- this.startup = startup;
405
- }
406
- /** @internal */
407
- async init() {
408
- if (this.isInitialized) return this;
409
- if (this.startFailed) throw new SeedcordError(SeedcordErrorCode.LifecycleRestartAfterFailure);
410
- this.registerPluginTasks();
411
- const startupSettled = Promise.withResolvers();
412
- this.shutdown.gateOnStartup(startupSettled.promise);
413
- try {
414
- await this.startup.run();
415
- } catch (caught) {
416
- await this.rollback();
417
- throw caught;
418
- } finally {
419
- startupSettled.resolve();
420
- }
421
- this.isInitialized = true;
422
- return this;
423
- }
424
- /** @internal codegen reads these to emit the `Core` augmentation */
425
- get pluginKeys() {
426
- return this.attachments.map((attachment) => attachment.key);
427
- }
428
- /** @internal so the next host can construct */
429
- static reset() {
430
- Pluggable.liveShutdown?.removeSignalHandlers();
431
- Pluggable.liveShutdown = void 0;
432
- Pluggable.isInstantiated = false;
433
- }
434
- /**
435
- * Attaches a plugin to this instance.
436
- *
437
- * The plugin initializes during startup, after every plugin attached before it, and becomes
438
- * available as a property on `core`. `seedcord codegen` writes the `Core` augmentation that
439
- * types it.
440
- *
441
- * A plugin declaring a `transport` or `runtime` this host does not run is a compile error on
442
- * this call. An edge host takes no plugins at all. A plugin constructor narrowing its first
443
- * parameter past `CoreBase` is a compile error here too. Read the transport `Core` off `this.core`.
444
- *
445
- * @typeParam Key - The property name for accessing the plugin
446
- * @typeParam Ctor - The plugin constructor type
447
- * @param key - Property name to access the plugin instance
448
- * @param Plugin - Plugin constructor class
449
- * @param args - Additional arguments to pass to the plugin constructor
450
- * @returns This instance with the plugin attached as a typed property
451
- * @throws A **SeedcordError** When called after initialization or if key already exists or is reserved
452
- * @example
453
- * ```typescript
454
- * seedcord.attach('db', Mongoose, { uri: 'mongodb://...', name: 'seedcord', dir: ... })
455
- * ```
456
- */
457
- attach(key, Plugin, ...args) {
458
- if (this.isInitialized) throw new SeedcordError(SeedcordErrorCode.CorePluginAfterInit);
459
- if (RESERVED_KEYS.has(key)) throw new SeedcordError(SeedcordErrorCode.CorePluginReservedChannel, [key]);
460
- if (key in this) throw new SeedcordError(SeedcordErrorCode.CorePluginKeyExists, [key]);
461
- const instance = new Plugin(this, ...args);
462
- pluginLoggerOf(instance).setChannel(key);
463
- this.plugins.push(instance);
464
- this.attachments.push({
465
- key,
466
- instance
467
- });
468
- return Object.assign(this, { [key]: instance });
469
- }
470
- registerPluginTasks() {
471
- if (this.pluginTasksRegistered) return;
472
- this.pluginTasksRegistered = true;
473
- const groups = /* @__PURE__ */ new Map();
474
- for (const attachment of this.attachments) {
475
- const phase = resolvedLifecycleSpecOf(attachment.instance).init.phase;
476
- const group = groups.get(phase) ?? [];
477
- group.push(attachment);
478
- groups.set(phase, group);
479
- }
480
- for (const [phase, group] of groups) {
481
- if (phase === 3) continue;
482
- const budget = group.reduce((sum, a) => sum + resolvedLifecycleSpecOf(a.instance).init.timeout, 0);
483
- this.startup.addTask(phase, "plugins-init", () => this.runInits(group), budget);
484
- }
485
- this.registerReadyTask(groups.get(3) ?? []);
486
- }
487
- async runInits(group) {
488
- for (const attachment of group) {
489
- const { key, instance } = attachment;
490
- const spec = resolvedLifecycleSpecOf(instance);
491
- pluginLoggerOf(instance).utils.initialization(key, "start");
492
- await withTimeout(`Plugin (${key})`, () => instance.init(), spec.init.timeout);
493
- pluginLoggerOf(instance).utils.initialization(key, "end");
494
- this.completedInits.add(attachment);
495
- if (instance.dispose) this.registerDisposeTask(spec.dispose.phase);
496
- }
497
- }
498
- registerReadyTask(readyInits) {
499
- const steps = this.attachments.reduce((acc, a) => {
500
- const ready = a.instance.ready?.bind(a.instance);
501
- if (ready) acc.push({
502
- key: a.key,
503
- run: ready,
504
- timeout: resolvedLifecycleSpecOf(a.instance).ready.timeout
505
- });
506
- return acc;
507
- }, []);
508
- if (readyInits.length === 0 && steps.length === 0) return;
509
- const budget = readyInits.reduce((sum, a) => sum + resolvedLifecycleSpecOf(a.instance).init.timeout, 0) + steps.reduce((sum, step) => sum + step.timeout, 0);
510
- this.startup.addTask(3, "plugins-ready", async () => {
511
- await this.runInits(readyInits);
512
- for (const step of steps) await withTimeout(`Plugin:${step.key}:ready`, step.run, step.timeout);
513
- }, budget);
514
- }
515
- registerDisposeTask(phase) {
516
- if (this.disposePhases.has(phase)) return;
517
- this.disposePhases.add(phase);
518
- const budget = this.attachments.reduce((sum, a) => {
519
- const spec = resolvedLifecycleSpecOf(a.instance);
520
- return a.instance.dispose && spec.dispose.phase === phase ? sum + spec.dispose.timeout : sum;
521
- }, 0);
522
- this.shutdown.addTask(phase, "plugins-dispose", () => this.runDisposals(phase), budget);
523
- }
524
- async runDisposals(phase) {
525
- const failures = [];
526
- await this.disposeCompleted(phase, (caught) => failures.push(caught));
527
- if (failures.length === 1) throw failures[0];
528
- if (failures.length > 1) throw new SeedcordAggregateError(SeedcordErrorCode.PluginDisposeFailures, failures, [failures.length]);
529
- }
530
- async disposeCompleted(phase, onError) {
531
- for (const attachment of [...this.attachments].reverse()) {
532
- if (!this.completedInits.has(attachment)) continue;
533
- const dispose = attachment.instance.dispose?.bind(attachment.instance);
534
- if (!dispose) continue;
535
- const spec = resolvedLifecycleSpecOf(attachment.instance);
536
- if (phase !== void 0 && spec.dispose.phase !== phase) continue;
537
- try {
538
- await withTimeout(`Plugin:${attachment.key}:dispose`, dispose, spec.dispose.timeout);
539
- } catch (caught) {
540
- onError(caught);
541
- }
542
- }
543
- }
544
- async rollback() {
545
- this.startFailed = true;
546
- await this.disposeCompleted(void 0, (caught) => this.pluginLogger.warn("rollback dispose failed", caught));
547
- this.completedInits.clear();
548
- }
549
- };
550
-
551
110
  //#endregion
552
111
  //#region src/node/subscribers/SubscriberLoader.ts
553
112
  var SubscriberLoader = class {
@@ -573,14 +132,14 @@ var SubscriberLoader = class {
573
132
  async init() {
574
133
  if (this.isInitialized) return;
575
134
  this.isInitialized = true;
576
- this.bus.registerDefaults();
135
+ this.bus[RegisterDefaults]();
577
136
  const { directory } = this;
578
137
  if (directory) {
579
138
  busLoggerOf(this.bus).debug(paint.mute(directory));
580
139
  await this.load(directory);
581
- busLoggerOf(this.bus).utils.list([`${paint.iris.bold(this.bus.registeredCount)} subscribers`], paint.mint.bold("Loaded"), "debug");
140
+ busLoggerOf(this.bus).utils.list([`${paint.iris.bold(this.bus[RegisteredCount])} subscribers`], paint.mint.bold("Loaded"), "debug");
582
141
  }
583
- if (!Envapter.isTest) await this.bus.verifyWebhooks();
142
+ if (!Envapter.isTest) await this.bus[VerifyWebhooks]();
584
143
  }
585
144
  /** @internal */
586
145
  async onHmr(event) {
@@ -598,10 +157,10 @@ var SubscriberLoader = class {
598
157
  });
599
158
  }
600
159
  registerSubscriber(ctor) {
601
- this.bus.register(registrationFor(ctor));
160
+ this.bus[RegisterSubscriber](registrationFor(ctor));
602
161
  }
603
162
  unregisterSubscriber(ctor, artifacts) {
604
- this.bus.unregister(ctor, artifacts);
163
+ this.bus[UnregisterSubscriber](ctor, artifacts);
605
164
  }
606
165
  getArtifacts(ctor) {
607
166
  return [Reflect.getMetadata(SubscribeMetadataKey, ctor).subscriber];
@@ -623,7 +182,7 @@ function indexById(commands) {
623
182
  * @internal
624
183
  */
625
184
  var CommandRegistry = class {
626
- options;
185
+ core;
627
186
  logger = new Logger("Commands", { channel: "commands" });
628
187
  isInitialised = false;
629
188
  globalCommands = [];
@@ -633,13 +192,17 @@ var CommandRegistry = class {
633
192
  loadedCommands = [];
634
193
  hmrHandler;
635
194
  pendingEvents = /* @__PURE__ */ new Map();
636
- constructor(options) {
637
- this.options = options;
638
- if (!options.dir) throw new SeedcordError(SeedcordErrorCode.CoreControllerPathMissing, ["CommandRegistry", "commands"]);
195
+ injector = new CommandInjector();
196
+ dir;
197
+ constructor(core) {
198
+ this.core = core;
199
+ const dir = core.config.bot.commands.path;
200
+ if (!dir) throw new SeedcordError(SeedcordErrorCode.CoreControllerPathMissing, ["CommandRegistry", "commands"]);
201
+ this.dir = dir;
639
202
  if (!Envapter.isDevelopment && !Envapter.isTest) return;
640
203
  this.hmrHandler = new HmrModuleHandler({
641
- handlersDir: options.dir,
642
- isHandler: this.isCommandClass.bind(this),
204
+ handlersDir: dir,
205
+ isHandler: isCommandClass,
643
206
  registerHandler: this.registerCommand.bind(this),
644
207
  unregisterHandler: this.unregisterCommand.bind(this),
645
208
  getArtifacts: this.getArtifacts.bind(this),
@@ -656,7 +219,7 @@ var CommandRegistry = class {
656
219
  this.loading = true;
657
220
  this.loadedCommands.length = 0;
658
221
  try {
659
- await this.loadCommands(this.options.dir);
222
+ await this.loadCommands(this.dir);
660
223
  } finally {
661
224
  this.loading = false;
662
225
  }
@@ -694,7 +257,7 @@ var CommandRegistry = class {
694
257
  }
695
258
  /** @internal */
696
259
  async onHmr(event) {
697
- if (event.file.startsWith(resolve(process.cwd(), this.options.dir))) {
260
+ if (event.file.startsWith(resolve(process.cwd(), this.dir))) {
698
261
  this.pendingEvents.delete(event.file);
699
262
  this.pendingEvents.set(event.file, event);
700
263
  getDevChannel()?.send("seedcord:commands-update-prompt", { files: [...this.pendingEvents.keys()].map((f) => formatFilePath(f)) });
@@ -702,16 +265,12 @@ var CommandRegistry = class {
702
265
  }
703
266
  async loadCommands(dir) {
704
267
  await traverseDirectory(dir, (fullPath, rel, mod) => {
705
- for (const exported of Object.values(mod)) if (this.isCommandClass(exported)) {
268
+ for (const exported of Object.values(mod)) if (isCommandClass(exported)) {
706
269
  this.registerCommand(exported, rel);
707
270
  this.hmrHandler?.trackHandler(fullPath, exported);
708
271
  }
709
272
  });
710
273
  }
711
- isCommandClass(obj) {
712
- if (typeof obj !== "function") return false;
713
- return obj.prototype instanceof BuilderComponent && Reflect.hasMetadata(CommandMetadataKey, obj);
714
- }
715
274
  registerCommand(ctor, rel) {
716
275
  const meta = Reflect.getMetadata(CommandMetadataKey, ctor);
717
276
  if (!meta) return;
@@ -755,7 +314,7 @@ var CommandRegistry = class {
755
314
  global: /* @__PURE__ */ new Map(),
756
315
  guilds: /* @__PURE__ */ new Map()
757
316
  };
758
- const appId = this.options.applicationId();
317
+ const appId = this.core.applicationId;
759
318
  if (this.globalCommands.length > 0) {
760
319
  result.global = indexById(await this.put(Routes.applicationCommands(appId), this.globalCommands));
761
320
  const tag = this.globalCommands.length === 1 ? "command" : "commands";
@@ -767,12 +326,14 @@ var CommandRegistry = class {
767
326
  const tag = commands.length === 1 ? "command" : "commands";
768
327
  this.logger.utils.block(`Deployed ${paint.iris.bold(commands.length)} ${tag} to ${paint.sky.bold(guildId)}`, this.logger.utils.wrap(commands.map((command) => command.name)), "info");
769
328
  }
770
- this.options.onDeployed?.(result);
329
+ this.injector.inject(result, this.allCommands());
330
+ this.core.bus[PublishDefault]("commandsDeployed", deployedPayload(result));
771
331
  return result;
772
332
  }
773
333
  async put(route, commands) {
774
334
  const body = commands.map((command) => command.toJSON());
775
- return await this.options.rest.put(route, { body });
335
+ const { rest } = this.core;
336
+ return await rest.put(route, { body });
776
337
  }
777
338
  /** Every registered builder, global first. A guild command in N guilds appears once per guild. @internal */
778
339
  allCommands() {
@@ -787,7 +348,19 @@ var CommandRegistry = class {
787
348
  return contextMenuLeaves(this.allCommands());
788
349
  }
789
350
  };
351
+ function deployedPayload(result) {
352
+ const guilds = {};
353
+ for (const [guildId, deployed] of result.guilds) guilds[guildId] = [...deployed.values()];
354
+ return {
355
+ global: [...result.global.values()],
356
+ guilds
357
+ };
358
+ }
359
+
360
+ //#endregion
361
+ //#region src/node-internal.index.ts
362
+ assertNodeVersion(">=24.11", process.version);
790
363
 
791
364
  //#endregion
792
- export { CommandRegistry, CoordinatedShutdown, CoordinatedStartup, HealthCheck, HealthResponder, Pluggable, ShutdownPhase, StartupPhase, SubscriberLoader, settleWithin };
365
+ export { CommandRegistry, HealthCheck, HealthResponder, ShutdownPhase, StartupPhase, SubscriberLoader, settleWithin, shutdownOf };
793
366
  //# sourceMappingURL=node-internal.index.mjs.map