seedcord 0.15.0 → 0.16.0-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.
- package/dist/index.cjs +79 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +11 -11
- package/dist/index.mjs +80 -44
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -1774,6 +1774,16 @@ async function getConfirmation(interaction, prompt, options) {
|
|
|
1774
1774
|
return confirmed;
|
|
1775
1775
|
}
|
|
1776
1776
|
|
|
1777
|
+
//#endregion
|
|
1778
|
+
//#region src/hmr/devChannel.ts
|
|
1779
|
+
let channel;
|
|
1780
|
+
function setDevChannel(next) {
|
|
1781
|
+
channel = next;
|
|
1782
|
+
}
|
|
1783
|
+
function getDevChannel() {
|
|
1784
|
+
return channel;
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1777
1787
|
//#endregion
|
|
1778
1788
|
//#region src/interfaces/Plugin.ts
|
|
1779
1789
|
/**
|
|
@@ -1790,9 +1800,8 @@ var Plugin = class extends _seedcord_services.StrictEventEmitter {
|
|
|
1790
1800
|
this.pluggable = pluggable;
|
|
1791
1801
|
}
|
|
1792
1802
|
/**
|
|
1793
|
-
* Reloads plugin state on an HMR update.
|
|
1794
|
-
* @
|
|
1795
|
-
* @virtual Override this method to handle HMR updates
|
|
1803
|
+
* Reloads plugin state on an HMR update. The base implementation is a no-op, override it in your plugin.
|
|
1804
|
+
* @virtual
|
|
1796
1805
|
*/
|
|
1797
1806
|
onHmr(_event) {
|
|
1798
1807
|
return Promise.resolve();
|
|
@@ -1802,7 +1811,7 @@ var Plugin = class extends _seedcord_services.StrictEventEmitter {
|
|
|
1802
1811
|
* @param patterns - Glob patterns relative to the project root
|
|
1803
1812
|
*/
|
|
1804
1813
|
registerCriticalFiles(patterns) {
|
|
1805
|
-
|
|
1814
|
+
getDevChannel()?.send("seedcord:register-critical-files", { patterns });
|
|
1806
1815
|
}
|
|
1807
1816
|
/** @internal */
|
|
1808
1817
|
setMaxListeners(n) {
|
|
@@ -2718,15 +2727,7 @@ var HmrModuleHandler = class {
|
|
|
2718
2727
|
...options,
|
|
2719
2728
|
logger: options.logger.inChannel("hmr")
|
|
2720
2729
|
};
|
|
2721
|
-
|
|
2722
|
-
const data = {}.hot.data;
|
|
2723
|
-
data.hmr ??= {};
|
|
2724
|
-
this.store = data.hmr[this.options.name] = data.hmr[this.options.name] ?? {
|
|
2725
|
-
fileToHandlers: /* @__PURE__ */ new Map(),
|
|
2726
|
-
fileToMiddlewares: /* @__PURE__ */ new Map(),
|
|
2727
|
-
handlerArtifacts: /* @__PURE__ */ new Map()
|
|
2728
|
-
};
|
|
2729
|
-
} else this.store = {
|
|
2730
|
+
this.store = {
|
|
2730
2731
|
fileToHandlers: /* @__PURE__ */ new Map(),
|
|
2731
2732
|
fileToMiddlewares: /* @__PURE__ */ new Map(),
|
|
2732
2733
|
handlerArtifacts: /* @__PURE__ */ new Map()
|
|
@@ -2741,6 +2742,7 @@ var HmrModuleHandler = class {
|
|
|
2741
2742
|
async handle(event) {
|
|
2742
2743
|
const { file, affectedModules, type } = event;
|
|
2743
2744
|
const { logger, handlersDir, middlewaresDir } = this.options;
|
|
2745
|
+
const rollbackEnabled = event.rollback ?? true;
|
|
2744
2746
|
if (type === "delete" || type === "deleteDir") {
|
|
2745
2747
|
this.unload(file);
|
|
2746
2748
|
return;
|
|
@@ -2759,10 +2761,19 @@ var HmrModuleHandler = class {
|
|
|
2759
2761
|
const isHandler = fileToReload.startsWith(absHandlersDir);
|
|
2760
2762
|
const isMiddleware = absMiddlewaresDir ? fileToReload.startsWith(absMiddlewaresDir) : false;
|
|
2761
2763
|
if (!isHandler && !isMiddleware) continue;
|
|
2762
|
-
this.
|
|
2763
|
-
await this.reloadFile(fileToReload);
|
|
2764
|
+
await this.reloadWithRollback(fileToReload, rollbackEnabled);
|
|
2764
2765
|
}
|
|
2765
2766
|
}
|
|
2767
|
+
async reloadWithRollback(file, rollbackEnabled) {
|
|
2768
|
+
const { logger } = this.options;
|
|
2769
|
+
const snapshot = this.snapshotUnits(file);
|
|
2770
|
+
this.unload(file);
|
|
2771
|
+
if (await this.reloadFile(file)) return;
|
|
2772
|
+
this.unload(file);
|
|
2773
|
+
if (!rollbackEnabled) return;
|
|
2774
|
+
this.restoreUnits(file, snapshot);
|
|
2775
|
+
logger.warn(`${chalk.default.yellow.bold("Rolled back")} ${chalk.default.gray((0, _seedcord_utils.formatFilePath)(file))} to the last-good version`);
|
|
2776
|
+
}
|
|
2766
2777
|
/**
|
|
2767
2778
|
* Tracks a handler module as being loaded from a specific file.
|
|
2768
2779
|
* @param file - The file path the handler was loaded from.
|
|
@@ -2823,7 +2834,7 @@ var HmrModuleHandler = class {
|
|
|
2823
2834
|
const { logger, isHandler, isMiddleware, registerHandler, registerMiddleware } = this.options;
|
|
2824
2835
|
if (!(0, node_fs.existsSync)(file)) {
|
|
2825
2836
|
logger.info(`File does not exist, skipping reload: ${(0, _seedcord_utils.formatFilePath)(file)}`);
|
|
2826
|
-
return;
|
|
2837
|
+
return false;
|
|
2827
2838
|
}
|
|
2828
2839
|
try {
|
|
2829
2840
|
let fileUrl = (0, node_url.pathToFileURL)(file).href;
|
|
@@ -2840,8 +2851,26 @@ var HmrModuleHandler = class {
|
|
|
2840
2851
|
const name = val.name ?? "Middleware";
|
|
2841
2852
|
logger.info(`${chalk.default.blue.bold("Reloaded")} ${chalk.default.cyan.bold(name)} from ${chalk.default.gray((0, _seedcord_utils.formatFilePath)(file))}`);
|
|
2842
2853
|
}
|
|
2854
|
+
return true;
|
|
2843
2855
|
} catch (error) {
|
|
2844
2856
|
logger.error(`Failed to reload file: ${file}`, error);
|
|
2857
|
+
return false;
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2860
|
+
snapshotUnits(file) {
|
|
2861
|
+
return {
|
|
2862
|
+
handlers: Array.from(this.store.fileToHandlers.get(file) ?? []),
|
|
2863
|
+
middlewares: Array.from(this.store.fileToMiddlewares.get(file) ?? [])
|
|
2864
|
+
};
|
|
2865
|
+
}
|
|
2866
|
+
restoreUnits(file, snapshot) {
|
|
2867
|
+
for (const handler of snapshot.handlers) {
|
|
2868
|
+
this.options.registerHandler(handler, file);
|
|
2869
|
+
this.trackHandler(file, handler);
|
|
2870
|
+
}
|
|
2871
|
+
if (this.options.registerMiddleware) for (const middleware of snapshot.middlewares) {
|
|
2872
|
+
this.options.registerMiddleware(middleware, file);
|
|
2873
|
+
this.trackMiddleware(file, middleware);
|
|
2845
2874
|
}
|
|
2846
2875
|
}
|
|
2847
2876
|
};
|
|
@@ -2895,7 +2924,7 @@ function slashRouteLeaves(commands) {
|
|
|
2895
2924
|
* Manages Discord application command registration and deployment.
|
|
2896
2925
|
*
|
|
2897
2926
|
* Scans command directories, builds command structures, and registers both global and guild-scoped commands
|
|
2898
|
-
* to Discord's API. Accessed via `core.bot.commands
|
|
2927
|
+
* to Discord's API. Accessed via `core.bot.commands`. Do not construct it directly.
|
|
2899
2928
|
*/
|
|
2900
2929
|
var CommandRegistry = class {
|
|
2901
2930
|
core;
|
|
@@ -2920,8 +2949,7 @@ var CommandRegistry = class {
|
|
|
2920
2949
|
registerHandler: this.registerCommand.bind(this),
|
|
2921
2950
|
unregisterHandler: this.unregisterCommand.bind(this),
|
|
2922
2951
|
getArtifacts: this.getArtifacts.bind(this),
|
|
2923
|
-
logger: this.logger
|
|
2924
|
-
name: "Commands"
|
|
2952
|
+
logger: this.logger
|
|
2925
2953
|
});
|
|
2926
2954
|
}
|
|
2927
2955
|
getArtifacts(ctor) {
|
|
@@ -2939,7 +2967,7 @@ var CommandRegistry = class {
|
|
|
2939
2967
|
global: this.globalCommands.length,
|
|
2940
2968
|
"guild groups": this.guildCommands.size
|
|
2941
2969
|
});
|
|
2942
|
-
|
|
2970
|
+
getDevChannel()?.on("seedcord:refresh-commands", (data) => {
|
|
2943
2971
|
this.refresh(data.shouldRefresh);
|
|
2944
2972
|
});
|
|
2945
2973
|
}
|
|
@@ -2961,7 +2989,7 @@ var CommandRegistry = class {
|
|
|
2961
2989
|
if (commandsDir && event.file.startsWith((0, node_path.resolve)(process.cwd(), commandsDir))) {
|
|
2962
2990
|
this.pendingEvents.delete(event.file);
|
|
2963
2991
|
this.pendingEvents.set(event.file, event);
|
|
2964
|
-
|
|
2992
|
+
getDevChannel()?.send("seedcord:commands-update-prompt", { files: Array.from(this.pendingEvents.keys()).map((f) => (0, _seedcord_utils.formatFilePath)(f)) });
|
|
2965
2993
|
} else await this.hmrHandler?.handle(event);
|
|
2966
2994
|
}
|
|
2967
2995
|
async loadCommands(dir) {
|
|
@@ -3295,8 +3323,7 @@ var EventDispatcher = class {
|
|
|
3295
3323
|
unregisterHandler: this.unregisterHandler.bind(this),
|
|
3296
3324
|
unregisterMiddleware: this.unregisterMiddleware.bind(this),
|
|
3297
3325
|
getArtifacts: this.getArtifacts.bind(this),
|
|
3298
|
-
logger: this.logger
|
|
3299
|
-
name: "Event"
|
|
3326
|
+
logger: this.logger
|
|
3300
3327
|
});
|
|
3301
3328
|
}
|
|
3302
3329
|
getArtifacts(ctor) {
|
|
@@ -3357,7 +3384,6 @@ var EventDispatcher = class {
|
|
|
3357
3384
|
if (handlers.length === 0) this.eventMap.delete(event);
|
|
3358
3385
|
}
|
|
3359
3386
|
}
|
|
3360
|
-
this.executedOnceHandlers.delete(handlerClass);
|
|
3361
3387
|
}
|
|
3362
3388
|
unregisterMiddleware(middlewareCtor) {
|
|
3363
3389
|
const index = this.middlewares.findIndex((entry) => entry.ctor === middlewareCtor);
|
|
@@ -3441,7 +3467,10 @@ var EventDispatcher = class {
|
|
|
3441
3467
|
if (handlersToExecute.length === 0) return;
|
|
3442
3468
|
if (!await this.runMiddlewares(eventName, args)) return;
|
|
3443
3469
|
for (const entry of handlersToExecute) {
|
|
3444
|
-
if (entry.frequency === "once")
|
|
3470
|
+
if (entry.frequency === "once") {
|
|
3471
|
+
if (this.executedOnceHandlers.has(entry.ctor)) continue;
|
|
3472
|
+
this.executedOnceHandlers.add(entry.ctor);
|
|
3473
|
+
}
|
|
3445
3474
|
await this.processHandler(eventName, entry.ctor, args);
|
|
3446
3475
|
}
|
|
3447
3476
|
}
|
|
@@ -3571,13 +3600,12 @@ var InteractionDispatcher = class {
|
|
|
3571
3600
|
unregisterHandler: this.unregisterHandler.bind(this),
|
|
3572
3601
|
unregisterMiddleware: this.unregisterMiddleware.bind(this),
|
|
3573
3602
|
getArtifacts: this.getArtifacts.bind(this),
|
|
3574
|
-
logger: this.logger
|
|
3575
|
-
name: "Interaction"
|
|
3603
|
+
logger: this.logger
|
|
3576
3604
|
});
|
|
3577
3605
|
}
|
|
3578
3606
|
/**
|
|
3579
3607
|
* Warns for each command route with no registered `@SlashRoute` handler, which would fall through to
|
|
3580
|
-
* UnhandledEvent at runtime.
|
|
3608
|
+
* UnhandledEvent at runtime. A bot may route commands outside the registry, so this does not throw.
|
|
3581
3609
|
*
|
|
3582
3610
|
* @internal
|
|
3583
3611
|
*/
|
|
@@ -3655,12 +3683,9 @@ var InteractionDispatcher = class {
|
|
|
3655
3683
|
registerMiddleware(middlewareCtor, relativePath) {
|
|
3656
3684
|
const metadata = Reflect.getMetadata(MiddlewareMetadataKey, middlewareCtor);
|
|
3657
3685
|
if (metadata?.type !== "interaction") return;
|
|
3658
|
-
|
|
3659
|
-
if (
|
|
3660
|
-
|
|
3661
|
-
priority: metadata.priority
|
|
3662
|
-
};
|
|
3663
|
-
else this.middlewares.push({
|
|
3686
|
+
if (this.middlewares.some((entry) => entry.ctor === middlewareCtor)) return;
|
|
3687
|
+
if (this.middlewares.some((entry) => entry.ctor.name === middlewareCtor.name)) throw new _seedcord_errors_internal.SeedcordError(_seedcord_errors.SeedcordErrorCode.InteractionDuplicateMiddleware, [middlewareCtor.name]);
|
|
3688
|
+
this.middlewares.push({
|
|
3664
3689
|
ctor: middlewareCtor,
|
|
3665
3690
|
priority: metadata.priority
|
|
3666
3691
|
});
|
|
@@ -3676,12 +3701,22 @@ var InteractionDispatcher = class {
|
|
|
3676
3701
|
return obj.prototype instanceof InteractionMiddleware && Reflect.hasMetadata(MiddlewareMetadataKey, obj);
|
|
3677
3702
|
}
|
|
3678
3703
|
registerHandler(handlerClass, relativePath) {
|
|
3704
|
+
const writes = [];
|
|
3679
3705
|
for (const [routeType, map] of this.routeTypes) {
|
|
3680
3706
|
const meta = Reflect.getMetadata(InteractionRouteKeys[routeType], handlerClass);
|
|
3681
3707
|
if (!areRoutes(meta)) continue;
|
|
3682
|
-
|
|
3708
|
+
for (const route of meta) {
|
|
3709
|
+
const existing = map.get(route);
|
|
3710
|
+
if (existing && existing !== handlerClass) throw new _seedcord_errors_internal.SeedcordError(_seedcord_errors.SeedcordErrorCode.InteractionDuplicateRoute, [
|
|
3711
|
+
route,
|
|
3712
|
+
existing.name,
|
|
3713
|
+
handlerClass.name
|
|
3714
|
+
]);
|
|
3715
|
+
writes.push([map, route]);
|
|
3716
|
+
}
|
|
3683
3717
|
this.logger.utils.registration(handlerClass.name, (0, _seedcord_utils.formatFilePath)(relativePath));
|
|
3684
3718
|
}
|
|
3719
|
+
for (const [map, route] of writes) map.set(route, handlerClass);
|
|
3685
3720
|
}
|
|
3686
3721
|
/** @internal For use in dev mode */
|
|
3687
3722
|
async onHmr(event) {
|
|
@@ -3932,9 +3967,11 @@ var HmrManager = class {
|
|
|
3932
3967
|
constructor() {}
|
|
3933
3968
|
/** @internal */
|
|
3934
3969
|
init() {
|
|
3935
|
-
if ({}.hot
|
|
3970
|
+
if (!{}.hot) return;
|
|
3971
|
+
setDevChannel((0, _seedcord_types_internal.wrapHot)({}.hot));
|
|
3972
|
+
if (envapt.Envapter.isDevelopment || envapt.Envapter.isTest) {
|
|
3936
3973
|
this.logger.info("Enabled");
|
|
3937
|
-
(
|
|
3974
|
+
getDevChannel()?.on("seedcord:hmr", (payload) => {
|
|
3938
3975
|
const affected = payload.affectedModules?.length ?? 0;
|
|
3939
3976
|
this.logger.info(`${chalk.default.bold("1")} module changed, ${chalk.default.bold(affected)} affected modules`);
|
|
3940
3977
|
if (payload.affectedModules) this.logger.utils.list(payload.affectedModules.map((mod) => (0, _seedcord_utils.formatFilePath)(mod)), "Affected modules: ");
|
|
@@ -4131,8 +4168,8 @@ var UnhandledErrorContainer = class extends _seedcord_kit.BuilderComponent {
|
|
|
4131
4168
|
*
|
|
4132
4169
|
* Provides a centralized system for registering and executing custom subscribers
|
|
4133
4170
|
* throughout the application lifecycle. Bus subscribers are loaded from configured directories
|
|
4134
|
-
* and can be triggered programmatically or by framework events. Accessed via `core.bus
|
|
4135
|
-
*
|
|
4171
|
+
* and can be triggered programmatically or by framework events. Accessed via `core.bus`. Do not
|
|
4172
|
+
* construct it directly.
|
|
4136
4173
|
*/
|
|
4137
4174
|
var Bus = class extends Plugin {
|
|
4138
4175
|
core;
|
|
@@ -4154,8 +4191,7 @@ var Bus = class extends Plugin {
|
|
|
4154
4191
|
registerHandler: this.registerSubscriber.bind(this),
|
|
4155
4192
|
unregisterHandler: this.unregisterSubscriber.bind(this),
|
|
4156
4193
|
getArtifacts: this.getArtifacts.bind(this),
|
|
4157
|
-
logger: this.logger
|
|
4158
|
-
name: "Subscribers"
|
|
4194
|
+
logger: this.logger
|
|
4159
4195
|
});
|
|
4160
4196
|
}
|
|
4161
4197
|
}
|
|
@@ -4213,7 +4249,6 @@ var Bus = class extends Plugin {
|
|
|
4213
4249
|
const index = handlers.findIndex((entry) => entry.ctor === handler);
|
|
4214
4250
|
if (index !== -1) handlers.splice(index, 1);
|
|
4215
4251
|
}
|
|
4216
|
-
this.executedOnceHandlers.delete(handler);
|
|
4217
4252
|
}
|
|
4218
4253
|
isSubscriber(obj) {
|
|
4219
4254
|
if (typeof obj !== "function") return false;
|
|
@@ -4347,6 +4382,7 @@ var Seedcord = class Seedcord extends Pluggable {
|
|
|
4347
4382
|
registerHmrAwareModules() {
|
|
4348
4383
|
this.startup.addTask(_seedcord_services.StartupPhase.Configuration, "HMR Registration", async () => {
|
|
4349
4384
|
this.hmrManager.register(this.bot);
|
|
4385
|
+
this.hmrManager.register(this.bus);
|
|
4350
4386
|
for (const plugin of this.plugins) this.hmrManager.register(plugin);
|
|
4351
4387
|
await Promise.resolve();
|
|
4352
4388
|
});
|
|
@@ -4356,7 +4392,7 @@ var Seedcord = class Seedcord extends Pluggable {
|
|
|
4356
4392
|
//#endregion
|
|
4357
4393
|
//#region src/index.ts
|
|
4358
4394
|
/** Package version */
|
|
4359
|
-
const version = "0.
|
|
4395
|
+
const version = "0.16.0-next.0";
|
|
4360
4396
|
|
|
4361
4397
|
//#endregion
|
|
4362
4398
|
exports.ArraySource = ArraySource;
|