@wolfstar/http-framework 3.2.1 → 3.3.0-next-20260901122142

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/esm/index.js CHANGED
@@ -5,12 +5,58 @@ import { AsyncEventEmitter } from "@vladfrangu/async_event_emitter";
5
5
  import { ApplicationCommandOptionType, ApplicationCommandType, ComponentType, InteractionResponseType, InteractionType, PermissionFlagsBits, Routes } from "discord-api-types/v10";
6
6
  import { createServer } from "node:http";
7
7
  import { Result, err, ok } from "@sapphire/result";
8
+ import { relative } from "node:path";
8
9
  import { Collection } from "@discordjs/collection";
9
10
  import { ContextMenuCommandBuilder, SlashCommandBuilder, SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder } from "@discordjs/builders";
10
11
  import { isJSONEncodable } from "@discordjs/util";
11
12
  import { webcrypto } from "node:crypto";
12
13
  import { TextDecoder } from "node:util";
13
14
 
15
+ //#region src/lib/ClientEvents.ts
16
+ /**
17
+ * The name of every event emitted by the {@link Client}, mirroring the keys of {@link ClientEvents}.
18
+ *
19
+ * @remarks
20
+ * Each member's value is the plain event name, so they are interchangeable with the string literals
21
+ * accepted by `Client#on`, `Client#emit`, and {@link Listener.Options.event}.
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * client.on(Events.CommandError, (error, context) => console.error(context.command.name, error));
26
+ * ```
27
+ *
28
+ * @since 3.4.0
29
+ */
30
+ let Events = /* @__PURE__ */ function(Events) {
31
+ Events["Error"] = "error";
32
+ Events["PluginLoaded"] = "pluginLoaded";
33
+ Events["CommandNameMissing"] = "commandNameMissing";
34
+ Events["CommandNameUnknown"] = "commandNameUnknown";
35
+ Events["CommandMethodUnknown"] = "commandMethodUnknown";
36
+ Events["CommandRun"] = "commandRun";
37
+ Events["CommandSuccess"] = "commandSuccess";
38
+ Events["CommandError"] = "commandError";
39
+ Events["CommandFinish"] = "commandFinish";
40
+ Events["AutocompleteRun"] = "autocompleteRun";
41
+ Events["AutocompleteSuccess"] = "autocompleteSuccess";
42
+ Events["AutocompleteError"] = "autocompleteError";
43
+ Events["AutocompleteFinish"] = "autocompleteFinish";
44
+ Events["InteractionHandlerNameInvalid"] = "interactionHandlerNameInvalid";
45
+ Events["InteractionHandlerNameUnknown"] = "interactionHandlerNameUnknown";
46
+ Events["InteractionHandlerRun"] = "interactionHandlerRun";
47
+ Events["InteractionHandlerSuccess"] = "interactionHandlerSuccess";
48
+ Events["InteractionHandlerError"] = "interactionHandlerError";
49
+ Events["InteractionHandlerFinish"] = "interactionHandlerFinish";
50
+ Events["HmrStart"] = "hmrStart";
51
+ Events["HmrStop"] = "hmrStop";
52
+ Events["HmrPiecesLoaded"] = "hmrPiecesLoaded";
53
+ Events["HmrPieceReloaded"] = "hmrPieceReloaded";
54
+ Events["HmrPieceUnloaded"] = "hmrPieceUnloaded";
55
+ Events["HmrError"] = "hmrError";
56
+ return Events;
57
+ }({});
58
+
59
+ //#endregion
14
60
  //#region src/lib/api/HttpCodes.ts
15
61
  let HttpCodes = /* @__PURE__ */ function(HttpCodes) {
16
62
  /**
@@ -391,42 +437,6 @@ let HttpCodes = /* @__PURE__ */ function(HttpCodes) {
391
437
  return HttpCodes;
392
438
  }({});
393
439
 
394
- //#endregion
395
- //#region src/lib/components/StringIdParser.ts
396
- var StringIdParser = class {
397
- run(customId) {
398
- if (customId.length === 0) return null;
399
- const index = customId.indexOf(".");
400
- if (index === -1) return {
401
- name: customId,
402
- content: null
403
- };
404
- return {
405
- name: customId.slice(0, index),
406
- content: customId.slice(index + 1).split(".").map((contentEntry) => contentEntry || null)
407
- };
408
- }
409
- };
410
-
411
- //#endregion
412
- //#region src/lib/types/Enums.ts
413
- let PluginHook = /* @__PURE__ */ function(PluginHook) {
414
- PluginHook["PreGenericsInitialization"] = "preGenericsInitialization";
415
- PluginHook["PreInitialization"] = "preInitialization";
416
- PluginHook["PostInitialization"] = "postInitialization";
417
- PluginHook["PreLoad"] = "preLoad";
418
- PluginHook["PostListen"] = "postListen";
419
- return PluginHook;
420
- }({});
421
-
422
- //#endregion
423
- //#region src/lib/plugins/symbols.ts
424
- const preGenericsInitialization = Symbol("HttpFrameworkPluginsPreGenericsInitialization");
425
- const preInitialization = Symbol("HttpFrameworkPluginsPreInitialization");
426
- const postInitialization = Symbol("HttpFrameworkPluginsPostInitialization");
427
- const preLoad = Symbol("HttpFrameworkPluginsPreLoad");
428
- const postListen = Symbol("HttpFrameworkPluginsPostListen");
429
-
430
440
  //#endregion
431
441
  //#region \0@oxc-project+runtime@0.144.0/helpers/esm/typeof.js
432
442
  function _typeof(o) {
@@ -469,6 +479,218 @@ function _defineProperty(e, r, t) {
469
479
  }) : e[r] = t, e;
470
480
  }
471
481
 
482
+ //#endregion
483
+ //#region \0@oxc-project+runtime@0.144.0/helpers/esm/checkPrivateRedeclaration.js
484
+ function _checkPrivateRedeclaration(e, t) {
485
+ if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object");
486
+ }
487
+
488
+ //#endregion
489
+ //#region \0@oxc-project+runtime@0.144.0/helpers/esm/classPrivateFieldInitSpec.js
490
+ function _classPrivateFieldInitSpec(e, t, a) {
491
+ _checkPrivateRedeclaration(e, t), t.set(e, a);
492
+ }
493
+
494
+ //#endregion
495
+ //#region \0@oxc-project+runtime@0.144.0/helpers/esm/assertClassBrand.js
496
+ function _assertClassBrand(e, t, n) {
497
+ if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n;
498
+ throw new TypeError("Private element is not present on this object");
499
+ }
500
+
501
+ //#endregion
502
+ //#region \0@oxc-project+runtime@0.144.0/helpers/esm/classPrivateFieldGet2.js
503
+ function _classPrivateFieldGet2(s, a) {
504
+ return s.get(_assertClassBrand(s, a));
505
+ }
506
+
507
+ //#endregion
508
+ //#region \0@oxc-project+runtime@0.144.0/helpers/esm/classPrivateFieldSet2.js
509
+ function _classPrivateFieldSet2(s, a, r) {
510
+ return s.set(_assertClassBrand(s, a), r), r;
511
+ }
512
+
513
+ //#endregion
514
+ //#region src/lib/hmr/HotModuleReloader.ts
515
+ var _watchers = /* @__PURE__ */ new WeakMap();
516
+ var _running = /* @__PURE__ */ new WeakMap();
517
+ /**
518
+ * Hot Module Reloading for every {@link Store} registered in {@link container.stores}.
519
+ *
520
+ * @remarks The reloader watches each store's registered paths and reacts to file system events by loading, reloading,
521
+ * and unloading the affected pieces in place, without restarting the process. It is a development-only utility: watching
522
+ * the file system in production adds overhead and reloads code that is not supposed to change, which is why it is
523
+ * opt-in.
524
+ * @since 3.3.0
525
+ * @example
526
+ * ```typescript
527
+ * const client = new Client({ hmr: { enabled: process.env.NODE_ENV !== 'production' } });
528
+ * await client.load();
529
+ * ```
530
+ */
531
+ var HotModuleReloader = class {
532
+ constructor(options = {}) {
533
+ _defineProperty(this, "options", void 0);
534
+ _classPrivateFieldInitSpec(this, _watchers, []);
535
+ _classPrivateFieldInitSpec(this, _running, false);
536
+ this.options = options;
537
+ }
538
+ /**
539
+ * Whether the reloader is currently watching for changes.
540
+ *
541
+ * @since 3.3.0
542
+ */
543
+ get running() {
544
+ return _classPrivateFieldGet2(_running, this);
545
+ }
546
+ /**
547
+ * The paths currently being watched, one entry per store path.
548
+ *
549
+ * @since 3.3.0
550
+ */
551
+ get paths() {
552
+ return _classPrivateFieldGet2(_watchers, this).flatMap((watcher) => Object.keys(watcher.getWatched()));
553
+ }
554
+ /**
555
+ * Starts watching every path registered in every store.
556
+ *
557
+ * @remarks This is a no-op when {@link HotModuleReloader.Options.enabled} is `false`, when the reloader is already
558
+ * running, or when no store has registered paths. `chokidar` is imported lazily, so applications that never enable
559
+ * HMR do not pay for loading it.
560
+ * @since 3.3.0
561
+ * @returns This instance, for chaining.
562
+ */
563
+ async start() {
564
+ if (_classPrivateFieldGet2(_running, this)) return this;
565
+ const { enabled = true, silent = false, ...chokidarOptions } = this.options;
566
+ if (!enabled) return this;
567
+ const { watch } = await import("chokidar");
568
+ const watchedPaths = [];
569
+ for (const store of container$1.stores.values()) {
570
+ const paths = [...store.paths];
571
+ if (paths.length === 0) continue;
572
+ watchedPaths.push(...paths);
573
+ _classPrivateFieldGet2(_watchers, this).push(watch(paths, {
574
+ ignoreInitial: true,
575
+ ...chokidarOptions
576
+ }).on("add", (path) => void this.handlePieceUpdate(store, path)).on("change", (path) => void this.handlePieceUpdate(store, path)).on("unlink", (path) => void this.handlePieceDelete(store, path)));
577
+ }
578
+ _classPrivateFieldSet2(_running, this, true);
579
+ if (!silent) console.info(`[HMR]: Enabled, watching ${watchedPaths.length} path(s) for piece changes.`);
580
+ container$1.client?.emit("hmrStart", watchedPaths);
581
+ return this;
582
+ }
583
+ /**
584
+ * Stops watching for changes and closes every watcher.
585
+ *
586
+ * @remarks Calling this on a reloader that is not running is a no-op. Already loaded pieces are left untouched.
587
+ * @since 3.3.0
588
+ */
589
+ async stop() {
590
+ if (!_classPrivateFieldGet2(_running, this)) return;
591
+ const watchers = _classPrivateFieldGet2(_watchers, this);
592
+ _classPrivateFieldSet2(_watchers, this, []);
593
+ _classPrivateFieldSet2(_running, this, false);
594
+ await Promise.all(watchers.map((watcher) => watcher.close()));
595
+ if (!this.options.silent) console.info("[HMR]: Disabled, no longer watching for piece changes.");
596
+ container$1.client?.emit("hmrStop");
597
+ }
598
+ /**
599
+ * Handles a file being added to, or modified in, one of the store's paths, reloading the piece it defines when it is
600
+ * already loaded, and loading it otherwise.
601
+ *
602
+ * @since 3.3.0
603
+ * @param store - The store the path belongs to.
604
+ * @param path - The full path of the file that changed.
605
+ */
606
+ async handlePieceUpdate(store, path) {
607
+ if (!store.strategy.filter(path)) return;
608
+ const piece = store.find((entry) => entry.location.full === path);
609
+ (await Result.fromAsync(async () => {
610
+ if (piece) {
611
+ await piece.reload();
612
+ if (!this.options.silent) console.info(`[HMR]: Reloaded '${piece.name}' from the '${store.name}' store.`);
613
+ container$1.client?.emit("hmrPieceReloaded", piece, path);
614
+ return;
615
+ }
616
+ const root = [...store.paths].find((storePath) => path.startsWith(storePath));
617
+ if (!root) throw new Error(`Could not find the root path for '${path}'.`);
618
+ const pieces = await store.load(root, relative(root, path));
619
+ if (!this.options.silent) {
620
+ const names = pieces.map((entry) => `'${entry.name}'`).join(", ");
621
+ console.info(`[HMR]: Loaded ${pieces.length} piece(s) into the '${store.name}' store: ${names}.`);
622
+ }
623
+ container$1.client?.emit("hmrPiecesLoaded", pieces, path);
624
+ })).inspectErr((error) => this.handleError(error, path));
625
+ }
626
+ /**
627
+ * Handles a file being removed from one of the store's paths, unloading the piece it defined.
628
+ *
629
+ * @since 3.3.0
630
+ * @param store - The store the path belongs to.
631
+ * @param path - The full path of the file that was deleted.
632
+ */
633
+ async handlePieceDelete(store, path) {
634
+ if (!store.strategy.filter(path)) return;
635
+ const piece = store.find((entry) => entry.location.full === path);
636
+ if (!piece) return;
637
+ (await Result.fromAsync(async () => {
638
+ await piece.unload();
639
+ if (!this.options.silent) console.info(`[HMR]: Unloaded '${piece.name}' from the '${store.name}' store.`);
640
+ container$1.client?.emit("hmrPieceUnloaded", piece, path);
641
+ })).inspectErr((error) => this.handleError(error, path));
642
+ }
643
+ /**
644
+ * Handles an error thrown while (re)loading or unloading a piece.
645
+ *
646
+ * @remarks Errors are never rethrown: a broken file must not take the process down, the user is expected to fix it
647
+ * and save again, which triggers a new reload.
648
+ * @since 3.3.0
649
+ * @param error - The error that was thrown.
650
+ * @param path - The full path of the file that was being processed.
651
+ */
652
+ handleError(error, path) {
653
+ if (!this.options.silent) console.error(`[HMR]: Failed to process '${path}'.`, error);
654
+ container$1.client?.emit("hmrError", error, path);
655
+ }
656
+ };
657
+
658
+ //#endregion
659
+ //#region src/lib/components/StringIdParser.ts
660
+ var StringIdParser = class {
661
+ run(customId) {
662
+ if (customId.length === 0) return null;
663
+ const index = customId.indexOf(".");
664
+ if (index === -1) return {
665
+ name: customId,
666
+ content: null
667
+ };
668
+ return {
669
+ name: customId.slice(0, index),
670
+ content: customId.slice(index + 1).split(".").map((contentEntry) => contentEntry || null)
671
+ };
672
+ }
673
+ };
674
+
675
+ //#endregion
676
+ //#region src/lib/types/Enums.ts
677
+ let PluginHook = /* @__PURE__ */ function(PluginHook) {
678
+ PluginHook["PreGenericsInitialization"] = "preGenericsInitialization";
679
+ PluginHook["PreInitialization"] = "preInitialization";
680
+ PluginHook["PostInitialization"] = "postInitialization";
681
+ PluginHook["PreLoad"] = "preLoad";
682
+ PluginHook["PostListen"] = "postListen";
683
+ return PluginHook;
684
+ }({});
685
+
686
+ //#endregion
687
+ //#region src/lib/plugins/symbols.ts
688
+ const preGenericsInitialization = Symbol("HttpFrameworkPluginsPreGenericsInitialization");
689
+ const preInitialization = Symbol("HttpFrameworkPluginsPreInitialization");
690
+ const postInitialization = Symbol("HttpFrameworkPluginsPostInitialization");
691
+ const preLoad = Symbol("HttpFrameworkPluginsPreLoad");
692
+ const postListen = Symbol("HttpFrameworkPluginsPostListen");
693
+
472
694
  //#endregion
473
695
  //#region src/lib/plugins/PluginManager.ts
474
696
  var PluginManager = class {
@@ -910,43 +1132,12 @@ function getLinkedMethod(object) {
910
1132
  return Reflect.get(object, linkSymbol) ?? null;
911
1133
  }
912
1134
 
913
- //#endregion
914
- //#region \0@oxc-project+runtime@0.144.0/helpers/esm/checkPrivateRedeclaration.js
915
- function _checkPrivateRedeclaration(e, t) {
916
- if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object");
917
- }
918
-
919
1135
  //#endregion
920
1136
  //#region \0@oxc-project+runtime@0.144.0/helpers/esm/classPrivateMethodInitSpec.js
921
1137
  function _classPrivateMethodInitSpec(e, a) {
922
1138
  _checkPrivateRedeclaration(e, a), a.add(e);
923
1139
  }
924
1140
 
925
- //#endregion
926
- //#region \0@oxc-project+runtime@0.144.0/helpers/esm/classPrivateFieldInitSpec.js
927
- function _classPrivateFieldInitSpec(e, t, a) {
928
- _checkPrivateRedeclaration(e, t), t.set(e, a);
929
- }
930
-
931
- //#endregion
932
- //#region \0@oxc-project+runtime@0.144.0/helpers/esm/assertClassBrand.js
933
- function _assertClassBrand(e, t, n) {
934
- if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n;
935
- throw new TypeError("Private element is not present on this object");
936
- }
937
-
938
- //#endregion
939
- //#region \0@oxc-project+runtime@0.144.0/helpers/esm/classPrivateFieldSet2.js
940
- function _classPrivateFieldSet2(s, a, r) {
941
- return s.set(_assertClassBrand(s, a), r), r;
942
- }
943
-
944
- //#endregion
945
- //#region \0@oxc-project+runtime@0.144.0/helpers/esm/classPrivateFieldGet2.js
946
- function _classPrivateFieldGet2(s, a) {
947
- return s.get(_assertClassBrand(s, a));
948
- }
949
-
950
1141
  //#endregion
951
1142
  //#region src/lib/interactions/resolvers/ChatInputCommandResolver.ts
952
1143
  var _data$1 = /* @__PURE__ */ new WeakMap();
@@ -3225,6 +3416,10 @@ var CommandLoaderStrategy = class extends LoaderStrategy {
3225
3416
  /**
3226
3417
  * Called when a command is unloaded.
3227
3418
  *
3419
+ * @remarks This also drops the command's {@link ApplicationCommandRegistryEntry} from the
3420
+ * {@link ApplicationCommandRegistry}. The registry is keyed by command class, and reloading a command evaluates its
3421
+ * module again, producing a brand new class: without this, the entry of the previous class would linger and the
3422
+ * command would be pushed to Discord twice.
3228
3423
  * @since 2.0.0
3229
3424
  * @param store - The command store.
3230
3425
  * @param piece - The command being unloaded.
@@ -3233,6 +3428,7 @@ var CommandLoaderStrategy = class extends LoaderStrategy {
3233
3428
  onUnload(store, piece) {
3234
3429
  if (piece.router.chatInputName) store.router.removeChatInputMapping(piece.router.chatInputName);
3235
3430
  for (const name of piece.router.contextMenuNames) store.router.removeContextMenuMapping(name);
3431
+ container$1.applicationCommandRegistry.delete(piece.constructor);
3236
3432
  return piece;
3237
3433
  }
3238
3434
  };
@@ -3611,6 +3807,7 @@ var Client = class Client extends AsyncEventEmitter {
3611
3807
  constructor(options = {}) {
3612
3808
  super();
3613
3809
  _defineProperty(this, "server", void 0);
3810
+ _defineProperty(this, "hmr", null);
3614
3811
  _defineProperty(this, "id", void 0);
3615
3812
  _defineProperty(this, "options", void 0);
3616
3813
  _defineProperty(this, "bodySizeLimit", void 0);
@@ -3681,6 +3878,10 @@ var Client = class Client extends AsyncEventEmitter {
3681
3878
  }
3682
3879
  if (options.baseUserDirectory !== null) container$1.stores.registerPath(options.baseUserDirectory);
3683
3880
  await container$1.stores.load();
3881
+ if (this.options.hmr && (this.options.hmr.enabled ?? true)) {
3882
+ this.hmr = new HotModuleReloader(this.options.hmr);
3883
+ await this.hmr.start();
3884
+ }
3684
3885
  }
3685
3886
  /**
3686
3887
  * Starts the HTTP server, listening for HTTP interactions.
@@ -4140,5 +4341,5 @@ _defineProperty(Plugin, preLoad, void 0);
4140
4341
  _defineProperty(Plugin, postListen, void 0);
4141
4342
 
4142
4343
  //#endregion
4143
- export { AliasPiece, AliasStore, ApplicationCommandRegistry, ApplicationCommandRegistryEntry, ApplyOptions, ArgumentError, AutocompleteInteraction, BaseInteraction, ChatInputCommandInteraction, ChatInputRouterError, ChatInputRouterErrors, Client, Command, CommandInteraction, CommandLoaderStrategy, CommandRegistry, CommandRouter, CommandStore, CommandStoreRouter, Enumerable, EnumerableMethod, HttpCodes, Identifiers, InteractionHandler, InteractionHandlerStore, Listener, ListenerLoaderStrategy, ListenerStore, LoaderError, Message, MessageComponentButtonInteraction, MessageComponentChannelSelectInteraction, MessageComponentInteraction, MessageComponentMentionableSelectInteraction, MessageComponentRoleSelectInteraction, MessageComponentStringSelectInteraction as MessageComponentSelectMenuInteraction, MessageComponentStringSelectInteraction, MessageComponentUserSelectInteraction, MessageContextMenuCommandInteraction, MissingExportsError, ModalSubmitInteraction, PartialMessage, Piece, Plugin, PluginHook, PluginManager, PreconditionError, RegisterCommand, RegisterMessageCommand, RegisterSubcommand, RegisterSubcommandGroup, RegisterUserCommand, RequiresClientPermissions, RequiresDMContext, RequiresGuildContext, RequiresUserPermissions, RestrictGuildIds, Store, StoreRegistry, StringIdParser, UserContextMenuCommandInteraction, UserError, applicationCommandRegistry, container, createClassDecorator, createFunctionPrecondition, createMethodDecorator, createProxy, extractTopLevelOptions, getMissingPermissions, makeInteraction, postInitialization, postListen, preGenericsInitialization, preInitialization, preLoad, resolvePermissions, restrictedGuildIdRegistry, toPermissionNames, transformAutocompleteInteraction, transformInteraction, transformMessageInteraction, transformUserInteraction };
4344
+ export { AliasPiece, AliasStore, ApplicationCommandRegistry, ApplicationCommandRegistryEntry, ApplyOptions, ArgumentError, AutocompleteInteraction, BaseInteraction, ChatInputCommandInteraction, ChatInputRouterError, ChatInputRouterErrors, Client, Command, CommandInteraction, CommandLoaderStrategy, CommandRegistry, CommandRouter, CommandStore, CommandStoreRouter, Enumerable, EnumerableMethod, Events, HotModuleReloader, HttpCodes, Identifiers, InteractionHandler, InteractionHandlerStore, Listener, ListenerLoaderStrategy, ListenerStore, LoaderError, Message, MessageComponentButtonInteraction, MessageComponentChannelSelectInteraction, MessageComponentInteraction, MessageComponentMentionableSelectInteraction, MessageComponentRoleSelectInteraction, MessageComponentStringSelectInteraction as MessageComponentSelectMenuInteraction, MessageComponentStringSelectInteraction, MessageComponentUserSelectInteraction, MessageContextMenuCommandInteraction, MissingExportsError, ModalSubmitInteraction, PartialMessage, Piece, Plugin, PluginHook, PluginManager, PreconditionError, RegisterCommand, RegisterMessageCommand, RegisterSubcommand, RegisterSubcommandGroup, RegisterUserCommand, RequiresClientPermissions, RequiresDMContext, RequiresGuildContext, RequiresUserPermissions, RestrictGuildIds, Store, StoreRegistry, StringIdParser, UserContextMenuCommandInteraction, UserError, applicationCommandRegistry, container, createClassDecorator, createFunctionPrecondition, createMethodDecorator, createProxy, extractTopLevelOptions, getMissingPermissions, makeInteraction, postInitialization, postListen, preGenericsInitialization, preInitialization, preLoad, resolvePermissions, restrictedGuildIdRegistry, toPermissionNames, transformAutocompleteInteraction, transformInteraction, transformMessageInteraction, transformUserInteraction };
4144
4345
  //# sourceMappingURL=index.js.map