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

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,6 +5,7 @@ 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";
@@ -391,42 +392,6 @@ let HttpCodes = /* @__PURE__ */ function(HttpCodes) {
391
392
  return HttpCodes;
392
393
  }({});
393
394
 
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
395
  //#endregion
431
396
  //#region \0@oxc-project+runtime@0.144.0/helpers/esm/typeof.js
432
397
  function _typeof(o) {
@@ -469,6 +434,218 @@ function _defineProperty(e, r, t) {
469
434
  }) : e[r] = t, e;
470
435
  }
471
436
 
437
+ //#endregion
438
+ //#region \0@oxc-project+runtime@0.144.0/helpers/esm/checkPrivateRedeclaration.js
439
+ function _checkPrivateRedeclaration(e, t) {
440
+ if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object");
441
+ }
442
+
443
+ //#endregion
444
+ //#region \0@oxc-project+runtime@0.144.0/helpers/esm/classPrivateFieldInitSpec.js
445
+ function _classPrivateFieldInitSpec(e, t, a) {
446
+ _checkPrivateRedeclaration(e, t), t.set(e, a);
447
+ }
448
+
449
+ //#endregion
450
+ //#region \0@oxc-project+runtime@0.144.0/helpers/esm/assertClassBrand.js
451
+ function _assertClassBrand(e, t, n) {
452
+ if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n;
453
+ throw new TypeError("Private element is not present on this object");
454
+ }
455
+
456
+ //#endregion
457
+ //#region \0@oxc-project+runtime@0.144.0/helpers/esm/classPrivateFieldGet2.js
458
+ function _classPrivateFieldGet2(s, a) {
459
+ return s.get(_assertClassBrand(s, a));
460
+ }
461
+
462
+ //#endregion
463
+ //#region \0@oxc-project+runtime@0.144.0/helpers/esm/classPrivateFieldSet2.js
464
+ function _classPrivateFieldSet2(s, a, r) {
465
+ return s.set(_assertClassBrand(s, a), r), r;
466
+ }
467
+
468
+ //#endregion
469
+ //#region src/lib/hmr/HotModuleReloader.ts
470
+ var _watchers = /* @__PURE__ */ new WeakMap();
471
+ var _running = /* @__PURE__ */ new WeakMap();
472
+ /**
473
+ * Hot Module Reloading for every {@link Store} registered in {@link container.stores}.
474
+ *
475
+ * @remarks The reloader watches each store's registered paths and reacts to file system events by loading, reloading,
476
+ * and unloading the affected pieces in place, without restarting the process. It is a development-only utility: watching
477
+ * the file system in production adds overhead and reloads code that is not supposed to change, which is why it is
478
+ * opt-in.
479
+ * @since 3.3.0
480
+ * @example
481
+ * ```typescript
482
+ * const client = new Client({ hmr: { enabled: process.env.NODE_ENV !== 'production' } });
483
+ * await client.load();
484
+ * ```
485
+ */
486
+ var HotModuleReloader = class {
487
+ constructor(options = {}) {
488
+ _defineProperty(this, "options", void 0);
489
+ _classPrivateFieldInitSpec(this, _watchers, []);
490
+ _classPrivateFieldInitSpec(this, _running, false);
491
+ this.options = options;
492
+ }
493
+ /**
494
+ * Whether the reloader is currently watching for changes.
495
+ *
496
+ * @since 3.3.0
497
+ */
498
+ get running() {
499
+ return _classPrivateFieldGet2(_running, this);
500
+ }
501
+ /**
502
+ * The paths currently being watched, one entry per store path.
503
+ *
504
+ * @since 3.3.0
505
+ */
506
+ get paths() {
507
+ return _classPrivateFieldGet2(_watchers, this).flatMap((watcher) => Object.keys(watcher.getWatched()));
508
+ }
509
+ /**
510
+ * Starts watching every path registered in every store.
511
+ *
512
+ * @remarks This is a no-op when {@link HotModuleReloader.Options.enabled} is `false`, when the reloader is already
513
+ * running, or when no store has registered paths. `chokidar` is imported lazily, so applications that never enable
514
+ * HMR do not pay for loading it.
515
+ * @since 3.3.0
516
+ * @returns This instance, for chaining.
517
+ */
518
+ async start() {
519
+ if (_classPrivateFieldGet2(_running, this)) return this;
520
+ const { enabled = true, silent = false, ...chokidarOptions } = this.options;
521
+ if (!enabled) return this;
522
+ const { watch } = await import("chokidar");
523
+ const watchedPaths = [];
524
+ for (const store of container$1.stores.values()) {
525
+ const paths = [...store.paths];
526
+ if (paths.length === 0) continue;
527
+ watchedPaths.push(...paths);
528
+ _classPrivateFieldGet2(_watchers, this).push(watch(paths, {
529
+ ignoreInitial: true,
530
+ ...chokidarOptions
531
+ }).on("add", (path) => void this.handlePieceUpdate(store, path)).on("change", (path) => void this.handlePieceUpdate(store, path)).on("unlink", (path) => void this.handlePieceDelete(store, path)));
532
+ }
533
+ _classPrivateFieldSet2(_running, this, true);
534
+ if (!silent) console.info(`[HMR]: Enabled, watching ${watchedPaths.length} path(s) for piece changes.`);
535
+ container$1.client?.emit("hmrStart", watchedPaths);
536
+ return this;
537
+ }
538
+ /**
539
+ * Stops watching for changes and closes every watcher.
540
+ *
541
+ * @remarks Calling this on a reloader that is not running is a no-op. Already loaded pieces are left untouched.
542
+ * @since 3.3.0
543
+ */
544
+ async stop() {
545
+ if (!_classPrivateFieldGet2(_running, this)) return;
546
+ const watchers = _classPrivateFieldGet2(_watchers, this);
547
+ _classPrivateFieldSet2(_watchers, this, []);
548
+ _classPrivateFieldSet2(_running, this, false);
549
+ await Promise.all(watchers.map((watcher) => watcher.close()));
550
+ if (!this.options.silent) console.info("[HMR]: Disabled, no longer watching for piece changes.");
551
+ container$1.client?.emit("hmrStop");
552
+ }
553
+ /**
554
+ * Handles a file being added to, or modified in, one of the store's paths, reloading the piece it defines when it is
555
+ * already loaded, and loading it otherwise.
556
+ *
557
+ * @since 3.3.0
558
+ * @param store - The store the path belongs to.
559
+ * @param path - The full path of the file that changed.
560
+ */
561
+ async handlePieceUpdate(store, path) {
562
+ if (!store.strategy.filter(path)) return;
563
+ const piece = store.find((entry) => entry.location.full === path);
564
+ (await Result.fromAsync(async () => {
565
+ if (piece) {
566
+ await piece.reload();
567
+ if (!this.options.silent) console.info(`[HMR]: Reloaded '${piece.name}' from the '${store.name}' store.`);
568
+ container$1.client?.emit("hmrPieceReloaded", piece, path);
569
+ return;
570
+ }
571
+ const root = [...store.paths].find((storePath) => path.startsWith(storePath));
572
+ if (!root) throw new Error(`Could not find the root path for '${path}'.`);
573
+ const pieces = await store.load(root, relative(root, path));
574
+ if (!this.options.silent) {
575
+ const names = pieces.map((entry) => `'${entry.name}'`).join(", ");
576
+ console.info(`[HMR]: Loaded ${pieces.length} piece(s) into the '${store.name}' store: ${names}.`);
577
+ }
578
+ container$1.client?.emit("hmrPiecesLoaded", pieces, path);
579
+ })).inspectErr((error) => this.handleError(error, path));
580
+ }
581
+ /**
582
+ * Handles a file being removed from one of the store's paths, unloading the piece it defined.
583
+ *
584
+ * @since 3.3.0
585
+ * @param store - The store the path belongs to.
586
+ * @param path - The full path of the file that was deleted.
587
+ */
588
+ async handlePieceDelete(store, path) {
589
+ if (!store.strategy.filter(path)) return;
590
+ const piece = store.find((entry) => entry.location.full === path);
591
+ if (!piece) return;
592
+ (await Result.fromAsync(async () => {
593
+ await piece.unload();
594
+ if (!this.options.silent) console.info(`[HMR]: Unloaded '${piece.name}' from the '${store.name}' store.`);
595
+ container$1.client?.emit("hmrPieceUnloaded", piece, path);
596
+ })).inspectErr((error) => this.handleError(error, path));
597
+ }
598
+ /**
599
+ * Handles an error thrown while (re)loading or unloading a piece.
600
+ *
601
+ * @remarks Errors are never rethrown: a broken file must not take the process down, the user is expected to fix it
602
+ * and save again, which triggers a new reload.
603
+ * @since 3.3.0
604
+ * @param error - The error that was thrown.
605
+ * @param path - The full path of the file that was being processed.
606
+ */
607
+ handleError(error, path) {
608
+ if (!this.options.silent) console.error(`[HMR]: Failed to process '${path}'.`, error);
609
+ container$1.client?.emit("hmrError", error, path);
610
+ }
611
+ };
612
+
613
+ //#endregion
614
+ //#region src/lib/components/StringIdParser.ts
615
+ var StringIdParser = class {
616
+ run(customId) {
617
+ if (customId.length === 0) return null;
618
+ const index = customId.indexOf(".");
619
+ if (index === -1) return {
620
+ name: customId,
621
+ content: null
622
+ };
623
+ return {
624
+ name: customId.slice(0, index),
625
+ content: customId.slice(index + 1).split(".").map((contentEntry) => contentEntry || null)
626
+ };
627
+ }
628
+ };
629
+
630
+ //#endregion
631
+ //#region src/lib/types/Enums.ts
632
+ let PluginHook = /* @__PURE__ */ function(PluginHook) {
633
+ PluginHook["PreGenericsInitialization"] = "preGenericsInitialization";
634
+ PluginHook["PreInitialization"] = "preInitialization";
635
+ PluginHook["PostInitialization"] = "postInitialization";
636
+ PluginHook["PreLoad"] = "preLoad";
637
+ PluginHook["PostListen"] = "postListen";
638
+ return PluginHook;
639
+ }({});
640
+
641
+ //#endregion
642
+ //#region src/lib/plugins/symbols.ts
643
+ const preGenericsInitialization = Symbol("HttpFrameworkPluginsPreGenericsInitialization");
644
+ const preInitialization = Symbol("HttpFrameworkPluginsPreInitialization");
645
+ const postInitialization = Symbol("HttpFrameworkPluginsPostInitialization");
646
+ const preLoad = Symbol("HttpFrameworkPluginsPreLoad");
647
+ const postListen = Symbol("HttpFrameworkPluginsPostListen");
648
+
472
649
  //#endregion
473
650
  //#region src/lib/plugins/PluginManager.ts
474
651
  var PluginManager = class {
@@ -910,43 +1087,12 @@ function getLinkedMethod(object) {
910
1087
  return Reflect.get(object, linkSymbol) ?? null;
911
1088
  }
912
1089
 
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
1090
  //#endregion
920
1091
  //#region \0@oxc-project+runtime@0.144.0/helpers/esm/classPrivateMethodInitSpec.js
921
1092
  function _classPrivateMethodInitSpec(e, a) {
922
1093
  _checkPrivateRedeclaration(e, a), a.add(e);
923
1094
  }
924
1095
 
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
1096
  //#endregion
951
1097
  //#region src/lib/interactions/resolvers/ChatInputCommandResolver.ts
952
1098
  var _data$1 = /* @__PURE__ */ new WeakMap();
@@ -3225,6 +3371,10 @@ var CommandLoaderStrategy = class extends LoaderStrategy {
3225
3371
  /**
3226
3372
  * Called when a command is unloaded.
3227
3373
  *
3374
+ * @remarks This also drops the command's {@link ApplicationCommandRegistryEntry} from the
3375
+ * {@link ApplicationCommandRegistry}. The registry is keyed by command class, and reloading a command evaluates its
3376
+ * module again, producing a brand new class: without this, the entry of the previous class would linger and the
3377
+ * command would be pushed to Discord twice.
3228
3378
  * @since 2.0.0
3229
3379
  * @param store - The command store.
3230
3380
  * @param piece - The command being unloaded.
@@ -3233,6 +3383,7 @@ var CommandLoaderStrategy = class extends LoaderStrategy {
3233
3383
  onUnload(store, piece) {
3234
3384
  if (piece.router.chatInputName) store.router.removeChatInputMapping(piece.router.chatInputName);
3235
3385
  for (const name of piece.router.contextMenuNames) store.router.removeContextMenuMapping(name);
3386
+ container$1.applicationCommandRegistry.delete(piece.constructor);
3236
3387
  return piece;
3237
3388
  }
3238
3389
  };
@@ -3611,6 +3762,7 @@ var Client = class Client extends AsyncEventEmitter {
3611
3762
  constructor(options = {}) {
3612
3763
  super();
3613
3764
  _defineProperty(this, "server", void 0);
3765
+ _defineProperty(this, "hmr", null);
3614
3766
  _defineProperty(this, "id", void 0);
3615
3767
  _defineProperty(this, "options", void 0);
3616
3768
  _defineProperty(this, "bodySizeLimit", void 0);
@@ -3681,6 +3833,10 @@ var Client = class Client extends AsyncEventEmitter {
3681
3833
  }
3682
3834
  if (options.baseUserDirectory !== null) container$1.stores.registerPath(options.baseUserDirectory);
3683
3835
  await container$1.stores.load();
3836
+ if (this.options.hmr && (this.options.hmr.enabled ?? true)) {
3837
+ this.hmr = new HotModuleReloader(this.options.hmr);
3838
+ await this.hmr.start();
3839
+ }
3684
3840
  }
3685
3841
  /**
3686
3842
  * Starts the HTTP server, listening for HTTP interactions.
@@ -4140,5 +4296,5 @@ _defineProperty(Plugin, preLoad, void 0);
4140
4296
  _defineProperty(Plugin, postListen, void 0);
4141
4297
 
4142
4298
  //#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 };
4299
+ export { AliasPiece, AliasStore, ApplicationCommandRegistry, ApplicationCommandRegistryEntry, ApplyOptions, ArgumentError, AutocompleteInteraction, BaseInteraction, ChatInputCommandInteraction, ChatInputRouterError, ChatInputRouterErrors, Client, Command, CommandInteraction, CommandLoaderStrategy, CommandRegistry, CommandRouter, CommandStore, CommandStoreRouter, Enumerable, EnumerableMethod, 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
4300
  //# sourceMappingURL=index.js.map