@seedcord/core 0.12.0-next.0 → 0.12.0-next.3

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 (41) hide show
  1. package/README.md +3 -3
  2. package/dist/{Bus-W1K-uMeO.mjs → Bus-VJw-QpoY.mjs} +110 -54
  3. package/dist/Bus-VJw-QpoY.mjs.map +1 -0
  4. package/dist/{CoordinatedShutdown-BVtNNSsF.d.mts → CoordinatedShutdown-fPKLWjc5.d.mts} +2 -2
  5. package/dist/{CoordinatedStartup-DA3gW8op.mjs → CoordinatedStartup-Zw_Lk7Zk.mjs} +3 -3
  6. package/dist/{CoordinatedStartup-DA3gW8op.mjs.map → CoordinatedStartup-Zw_Lk7Zk.mjs.map} +1 -1
  7. package/dist/HmrModuleHandler-Btgu8r96.mjs +165 -0
  8. package/dist/HmrModuleHandler-Btgu8r96.mjs.map +1 -0
  9. package/dist/{PluginHost-DWBgBS6Q.d.mts → PluginHost-DFnkIldj.d.mts} +10 -9
  10. package/dist/{PluginHost-CYe-UVpp.mjs → PluginHost-DTtxWRiL.mjs} +4 -4
  11. package/dist/PluginHost-DTtxWRiL.mjs.map +1 -0
  12. package/dist/{PluginLifecycle-DdwRzcDj.mjs → PluginLifecycle-hx5zUc-P.mjs} +4 -4
  13. package/dist/PluginLifecycle-hx5zUc-P.mjs.map +1 -0
  14. package/dist/{ServerHost-whpI0h4d.d.mts → ServerHost-B5o3ScCF.d.mts} +3 -3
  15. package/dist/{ServerHost-DHg-Y2_q.mjs → ServerHost-CDaEDR4C.mjs} +4 -4
  16. package/dist/{ServerHost-DHg-Y2_q.mjs.map → ServerHost-CDaEDR4C.mjs.map} +1 -1
  17. package/dist/hmr.index.d.mts +20 -20
  18. package/dist/hmr.index.mjs +1 -1
  19. package/dist/{index-Boo33hh3.d.mts → index-DGHng1IN.d.mts} +108 -193
  20. package/dist/index.d.mts +221 -74
  21. package/dist/index.mjs +222 -103
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/internal.index.d.mts +204 -82
  24. package/dist/internal.index.mjs +572 -73
  25. package/dist/internal.index.mjs.map +1 -1
  26. package/dist/node-internal.index.d.mts +4 -3
  27. package/dist/node-internal.index.mjs +3 -3
  28. package/dist/node.index.d.mts +2 -2
  29. package/dist/node.index.mjs +4 -4
  30. package/dist/{phases-Dojnr-ng.d.mts → phases-C2QCSqRu.d.mts} +60 -50
  31. package/dist/plugin.index.d.mts +1 -1
  32. package/dist/plugin.index.mjs +1 -1
  33. package/dist/{subscribers-D4_HZcgw.mjs → subscribers-CGuVjbrg.mjs} +139 -253
  34. package/dist/subscribers-CGuVjbrg.mjs.map +1 -0
  35. package/package.json +10 -9
  36. package/dist/Bus-W1K-uMeO.mjs.map +0 -1
  37. package/dist/HmrModuleHandler-BMD7dg8N.mjs +0 -162
  38. package/dist/HmrModuleHandler-BMD7dg8N.mjs.map +0 -1
  39. package/dist/PluginHost-CYe-UVpp.mjs.map +0 -1
  40. package/dist/PluginLifecycle-DdwRzcDj.mjs.map +0 -1
  41. package/dist/subscribers-D4_HZcgw.mjs.map +0 -1
@@ -1,14 +1,23 @@
1
- import { D as InteractionMiddlewareMetadataKey, E as InteractionMetadataKey, O as InteractionRouteKeys, T as InteractionKind, b as PublishDefault, j as BuilderComponent, x as CommandMetadataKey } from "./Bus-W1K-uMeO.mjs";
1
+ import { A as InteractionRouteKeys, C as CommandMetadataKey, D as InteractionKind, N as BuilderComponent, O as InteractionMetadataKey, S as assertUniqueKeys, k as InteractionMiddlewareMetadataKey, x as PublishDefault } from "./Bus-VJw-QpoY.mjs";
2
2
  import "reflect-metadata";
3
3
  import { CustomId, decodeFor } from "@seedcord/custom-id";
4
4
  import { TextDisplayBuilder } from "@discordjs/builders";
5
- import { ApplicationCommandType, PermissionFlagsBits, Routes } from "discord-api-types/v10";
5
+ import { ApplicationCommandType, Routes } from "discord-api-types/v10";
6
6
  import { SeedcordErrorCode, paint } from "@seedcord/errors";
7
7
  import { SeedcordError, SeedcordTypeError } from "@seedcord/errors/internal";
8
8
  import { Logger } from "@seedcord/logger";
9
9
  import { asError, isStringArray, pluralize, routeLeavesOf } from "@seedcord/utils/internal";
10
- import { prettify, toEpochSeconds } from "@seedcord/utils";
10
+ import { toEpochSeconds } from "@seedcord/utils";
11
11
 
12
+ //#region src/stops/NoticeCard.ts
13
+ var NoticeCard = class extends BuilderComponent {
14
+ constructor(description, title = "Cannot Proceed") {
15
+ super("container");
16
+ this.instance.addTextDisplayComponents(new TextDisplayBuilder().setContent(`### ${title}\n${description}`));
17
+ }
18
+ };
19
+
20
+ //#endregion
12
21
  //#region src/stops/Notice.ts
13
22
  /**
14
23
  * Base class for a user-facing refusal or a reported fault.
@@ -38,7 +47,7 @@ import { prettify, toEpochSeconds } from "@seedcord/utils";
38
47
  * super(`balance ${balance} is below the cost`);
39
48
  * }
40
49
  *
41
- * render(_ctx: RenderContext): ReplyResponse {
50
+ * override render(_ctx: RenderContext): ReplyResponse {
42
51
  * return { components: [new TooPoorCard(this.balance).component] };
43
52
  * }
44
53
  * }
@@ -63,7 +72,7 @@ var Notice = class extends Error {
63
72
  */
64
73
  ephemeral = true;
65
74
  /**
66
- * A short one-line reason. When every arm of an {@link or} gate refuses and each one sets this, `or`
75
+ * A short one-line reason. When every gate in an {@link or} refuses and each one sets this, `or`
67
76
  * throws a refusal listing them under `You need to meet at least one of these:`. Write a verb phrase that
68
77
  * finishes that line, for example, "be the bot owner".
69
78
  */
@@ -73,14 +82,13 @@ var Notice = class extends Error {
73
82
  this.name = new.target.name;
74
83
  Error.captureStackTrace(this, this.constructor);
75
84
  }
76
- };
77
-
78
- //#endregion
79
- //#region src/stops/NoticeCard.ts
80
- var NoticeCard = class extends BuilderComponent {
81
- constructor(description, title = "Cannot Proceed") {
82
- super("container");
83
- this.instance.addTextDisplayComponents(new TextDisplayBuilder().setContent(`### ${title}\n${description}`));
85
+ /**
86
+ * Builds what the user sees. Called fresh each time the denial is shown, so the builders are new
87
+ * and the bot color resolves at render time. By default it returns seedcord's refusal card with the message as
88
+ * its text. Override it to show your own components.
89
+ */
90
+ render(_ctx) {
91
+ return { components: [new NoticeCard(this.message).component] };
84
92
  }
85
93
  };
86
94
 
@@ -309,7 +317,7 @@ const KIND_LABELS = {
309
317
  [ApplicationCommandType.PrimaryEntryPoint]: "entry point command"
310
318
  };
311
319
  function multiGuildWarning({ name, type }) {
312
- const consequence = type === ApplicationCommandType.ChatInput ? "falling back to plain text (not clickable)" : "leaving its id unset";
320
+ const consequence = type === ApplicationCommandType.ChatInput ? "so its mention stays plain text (not clickable)" : "so its id stays unset";
313
321
  return `${paint.sky.bold(name)} is deployed to multiple guilds, ${consequence}.`;
314
322
  }
315
323
  function warnLinks(logger, { multiGuild, notInCode }) {
@@ -390,16 +398,21 @@ function interactionRoutesOf(constructor) {
390
398
  }
391
399
  return pairs;
392
400
  }
393
- function storeInteractionRoute(route, routes, constructor) {
401
+ function routeDecoratorOf(kind) {
402
+ return `@${kind.charAt(0).toUpperCase()}${kind.slice(1)}Route`;
403
+ }
404
+ function storeInteractionRoute(route, routes, constructor, fix = "Remove the repeat.") {
394
405
  const key = InteractionRouteKeys[route];
395
406
  const saved = Reflect.getMetadata(key, constructor);
396
407
  const existing = isStringArray(saved) ? saved : [];
397
408
  const toStore = typeof routes === "string" ? [routes] : routes;
409
+ const own = Reflect.getOwnMetadata(key, constructor);
410
+ assertUniqueKeys(routeDecoratorOf(route), constructor, [...isStringArray(own) ? own : [], ...toStore], fix);
398
411
  Reflect.defineMetadata(key, [...existing, ...toStore], constructor);
399
412
  Reflect.defineMetadata(InteractionMetadataKey, true, constructor);
400
413
  }
401
414
  function storeComponentRoute(route, defs, constructor) {
402
- storeInteractionRoute(route, defs.map((def) => def.prefix), constructor);
415
+ storeInteractionRoute(route, defs.map((def) => def.prefix), constructor, "Remove the repeat, or give each customId its own prefix.");
403
416
  Reflect.defineMetadata(ComponentDefsKey, defs, constructor);
404
417
  }
405
418
  function contextMenuRouteOf(kind) {
@@ -484,7 +497,7 @@ const ILLEGAL = {
484
497
  update: {
485
498
  "deferred-reply": {
486
499
  reason: "this interaction was deferred as a reply",
487
- alternative: "The placeholder is yours via edit(). update() rewrites a source message."
500
+ alternative: "update() only rewrites a source message. Use edit() to fill the placeholder."
488
501
  },
489
502
  replied: {
490
503
  reason: "this interaction was already replied to",
@@ -497,11 +510,11 @@ const ILLEGAL = {
497
510
  } },
498
511
  edit: { unacked: {
499
512
  reason: "nothing has been sent yet",
500
- alternative: "Send with reply() or defer() first, then edit() rewrites it."
513
+ alternative: "Send with reply() or defer() first. After that, edit() rewrites it."
501
514
  } },
502
515
  delete: { unacked: {
503
516
  reason: "nothing has been sent yet",
504
- alternative: "Acknowledge first with reply() or defer(), then delete() removes it."
517
+ alternative: "Acknowledge first with reply() or defer(). After that, delete() removes the reply."
505
518
  } },
506
519
  showModal: {
507
520
  "deferred-reply": showModalReason,
@@ -540,12 +553,15 @@ var AckTrace = class extends Error {
540
553
  };
541
554
 
542
555
  //#endregion
543
- //#region src/reply/responseReport.ts
544
- let replyLogger;
545
- function logger() {
546
- replyLogger ??= new Logger("Reply", { channel: "interactions" });
547
- return replyLogger;
556
+ //#region src/miscellaneous/lazyLogger.ts
557
+ function lazyLogger(label, options) {
558
+ let logger;
559
+ return () => logger ??= new Logger(label, options);
548
560
  }
561
+
562
+ //#endregion
563
+ //#region src/reply/responseReport.ts
564
+ const logger = lazyLogger("Reply", { channel: "interactions" });
549
565
  /** @internal */
550
566
  function publishResponse(telemetry, report) {
551
567
  const durationMs = performance.now() - report.startedAt;
@@ -725,122 +741,33 @@ function serializeReply(response, routeId) {
725
741
  };
726
742
  }
727
743
 
728
- //#endregion
729
- //#region src/gates/Gate.ts
730
- /**
731
- * Builds a {@link Gate} from a check. The check refuses by throwing a Notice or a Silence and passes
732
- * by returning. The required context is inferred from `ctx`, so annotate it as narrowly as the fields
733
- * the check reads. No annotation defaults to {@link GateContextBase}, an agnostic gate that fits every
734
- * handler.
735
- *
736
- * @typeParam Name - The gate's name, captured as a literal for mismatch errors.
737
- * @typeParam Ctx - The context the check reads, inferred from the `ctx` annotation.
738
- *
739
- * @param name - The gate's name, used in mismatch errors.
740
- * @param fn - The check, which refuses by throwing a Notice or a Silence and passes by returning.
741
- *
742
- * @see {@link defineEffectGate}
743
- * @see the `@Gated` decorator from your transport package
744
- *
745
- * @example
746
- * ```ts
747
- * // a gate factory that takes its own option and closes over it
748
- * function MinRoles(min: number): Gate<GateContextBase, 'MinRoles'> {
749
- * return defineGate('MinRoles', (ctx) => {
750
- * if (ctx.memberRoleIds.length < min) throw new NotEnoughRoles(min);
751
- * });
752
- * }
753
- * ```
754
- *
755
- * @example
756
- * ```ts
757
- * // agnostic gate (no ctx annotation): fits any handler
758
- * const Owner = defineGate('owner', (ctx) => {
759
- * if (!ctx.userId) throw new NotOwner();
760
- * });
761
- * ```
762
- */
763
- function defineGate(name, fn) {
764
- return {
765
- name,
766
- check: async (ctx) => fn(ctx)
767
- };
768
- }
769
- /**
770
- * Builds an {@link EffectGate} from a `check` and a `commit`. `check` peeks and refuses by throwing, and
771
- * `commit` applies the side effect, running only once the whole gate set passes so a later refusal never
772
- * commits. In an `or`, a refusing arm's queued commit is rolled back. This is how {@link Cooldown} peeks
773
- * in `check` and charges the slot in `commit`.
774
- *
775
- * @typeParam Name - The gate's literal name, used to name a mismatch error.
776
- * @typeParam Ctx - The context both `check` and `commit` read, inferred from the `ctx` annotation.
777
- *
778
- * @param name - The gate's name, used in mismatch errors.
779
- * @param check - Peeks and refuses by throwing, without applying the side effect.
780
- * @param commit - Applies the side effect, running only after the whole gate set passes.
781
- *
782
- * @see {@link defineGate}
783
- * @see the `@Gated` decorator from your transport package
784
- * @see {@link Cooldown}
785
- *
786
- * @example
787
- * ```ts
788
- * // an effect-gate factory that takes its own limit and closes over it
789
- * function UsesPerDay(max: number): EffectGate<GateContextBase, 'UsesPerDay'> {
790
- * return defineEffectGate(
791
- * 'UsesPerDay',
792
- * (ctx) => {
793
- * // peek and refuse by throwing. do not mutate yet
794
- * if (usedToday(ctx.userId) >= max) throw new OutOfUsesNotice(max);
795
- * },
796
- * (ctx) => {
797
- * // runs only after the whole gate set passes
798
- * recordUse(ctx.userId);
799
- * }
800
- * );
801
- * }
802
- * ```
803
- */
804
- function defineEffectGate(name, check, commit) {
805
- return {
806
- name,
807
- check: async (ctx) => check(ctx),
808
- commit: async (ctx) => commit(ctx)
809
- };
810
- }
811
-
812
744
  //#endregion
813
745
  //#region src/notices/index.ts
814
- var GateNotice = class extends Notice {
815
- render() {
816
- return { components: [new NoticeCard(this.message).component] };
817
- }
818
- };
819
- var NotOwner = class extends GateNotice {
820
- constructor(message = "Only the bot owner can use this.") {
821
- super(message);
746
+ var NotOwner = class extends Notice {
747
+ constructor() {
748
+ super("Only the bot owner can use this.");
822
749
  this.summary = "be the bot owner";
823
750
  }
824
751
  };
825
- var NotInGuild = class extends GateNotice {
826
- constructor(message = "This can only be used in a server.") {
827
- super(message);
752
+ var NotInGuild = class extends Notice {
753
+ constructor() {
754
+ super("This can only be used in a server.");
828
755
  this.summary = "be in a server";
829
756
  }
830
757
  };
831
- var NotInDm = class extends GateNotice {
832
- constructor(message = "This can only be used in a direct message.") {
833
- super(message);
758
+ var NotInDm = class extends Notice {
759
+ constructor() {
760
+ super("This can only be used in a direct message.");
834
761
  this.summary = "be in a direct message";
835
762
  }
836
763
  };
837
764
  function retryAt(resetAt) {
838
765
  return `<t:${toEpochSeconds(resetAt)}:R>`;
839
766
  }
840
- var OnCooldown = class extends GateNotice {
767
+ var OnCooldown = class extends Notice {
841
768
  resetAt;
842
- constructor(resetAt, message) {
843
- super(message ?? `You are doing that too fast. Try again ${retryAt(resetAt)}.`);
769
+ constructor(resetAt) {
770
+ super(`You are doing that too fast. Try again ${retryAt(resetAt)}.`);
844
771
  this.resetAt = resetAt;
845
772
  this.summary = `try again ${retryAt(resetAt)}`;
846
773
  }
@@ -864,45 +791,98 @@ var NeedsAny = class extends Notice {
864
791
  return { components: [new NoticeCard(`You need to meet at least one of these:\n${bullets}`).component] };
865
792
  }
866
793
  };
867
- var MissingRole = class extends GateNotice {
868
- constructor(message, roleId) {
869
- super(message ?? (roleId ? `You need the <@&${roleId}> role to use this.` : "You do not have the required role."));
870
- this.summary = roleId ? `hold the <@&${roleId}> role` : "hold the required role";
794
+ var MissingRole = class extends Notice {
795
+ constructor(roleId) {
796
+ super(`You need the <@&${roleId}> role to use this.`);
797
+ this.summary = `hold the <@&${roleId}> role`;
871
798
  }
872
799
  };
873
- var MissingPermissions = class extends Notice {
874
- subject;
875
- missingPerms;
876
- customLead;
877
- constructor(message, subject, missingPerms) {
878
- super(message ?? "A required permission is missing.");
879
- this.subject = subject;
880
- this.missingPerms = missingPerms;
881
- this.customLead = message;
882
- const names = missingPerms.join(", ");
883
- this.summary = subject === null ? `hold ${names}` : `${subject} needs ${names}`;
800
+ var PermissionsUnresolved = class extends Notice {
801
+ constructor() {
802
+ super("Your server member data could not be resolved. Try again.");
803
+ }
804
+ };
805
+ var PermissionListNotice = class extends Notice {
806
+ permissions;
807
+ lead;
808
+ constructor(message, subject, permissions, wording) {
809
+ super(message);
810
+ this.permissions = permissions;
811
+ const [prefix, words] = subject === null ? ["", wording.caller] : [`${subject} `, wording.subject];
812
+ this.lead = `${prefix}${words.lead}`;
813
+ this.summary = `${prefix}${words.summary} ${permissions.join(", ")}`;
884
814
  }
885
815
  render() {
886
- const bullets = this.missingPerms.map((perm) => `• ${perm}`).join("\n");
887
- const lead = this.customLead ?? `${this.subject === null ? "You are" : `${this.subject} is`} missing the following permission entries:`;
888
- return { components: [new NoticeCard(`${lead}\n${bullets}`).component] };
816
+ const bullets = this.permissions.map((perm) => `• ${perm}`).join("\n");
817
+ return { components: [new NoticeCard(`${this.lead}\n${bullets}`).component] };
889
818
  }
890
819
  };
891
- var HasDangerousPermissions = class extends Notice {
892
- subject;
893
- dangerousPerms;
894
- customLead;
895
- constructor(message, subject, dangerousPerms) {
896
- super(message ?? "A dangerous permission is enabled.");
897
- this.subject = subject;
898
- this.dangerousPerms = dangerousPerms;
899
- this.customLead = message;
900
- this.summary = `${subject} must not hold ${dangerousPerms.join(", ")}`;
820
+ var MissingPermissions = class extends PermissionListNotice {
821
+ constructor(subject, permissions) {
822
+ super("A required permission is missing.", subject, permissions, {
823
+ caller: {
824
+ lead: "You are missing the following permission entries:",
825
+ summary: "hold"
826
+ },
827
+ subject: {
828
+ lead: "is missing the following permission entries:",
829
+ summary: "needs"
830
+ }
831
+ });
901
832
  }
902
- render() {
903
- const bullets = this.dangerousPerms.map((perm) => `• ${perm}`).join("\n");
904
- const lead = this.customLead ?? `${this.subject} has the following permission entries that must not be enabled:`;
905
- return { components: [new NoticeCard(`${lead}\n${bullets}`).component] };
833
+ };
834
+ var HasPresentPermissions = class extends PermissionListNotice {
835
+ constructor(subject, permissions) {
836
+ super("A refused permission is held.", subject, permissions, {
837
+ caller: {
838
+ lead: "You hold permissions that aren't allowed here:",
839
+ summary: "not hold"
840
+ },
841
+ subject: {
842
+ lead: "holds permissions that aren't allowed here:",
843
+ summary: "must not hold"
844
+ }
845
+ });
846
+ }
847
+ };
848
+
849
+ //#endregion
850
+ //#region src/stops/Fault.ts
851
+ /**
852
+ * A generic fault you throw after catching an error you do not have a specific message for.
853
+ *
854
+ * The user sees a fixed generic reply with the tracking uuid, never the cause. `report` defaults to
855
+ * `true`, so the framework logs it and publishes it to the `handledException` bus. Pass `report: false`
856
+ * to show the generic reply without the bus publish. The original error is stored as the standard
857
+ * `cause`, so the real stack reaches the webhook. When the user should see a real message for a fault,
858
+ * subclass {@link Notice} and write your own `render` instead.
859
+ *
860
+ * The framework also renders this for an unhandled throw, where it points the user at
861
+ * `ctx.developerUsername`.
862
+ *
863
+ * @example
864
+ * ```ts
865
+ * import { Fault } from '@seedcord/gateway';
866
+ *
867
+ * try {
868
+ * await db.write(record);
869
+ * } catch (cause) {
870
+ * // user sees the generic reply with the uuid, and the real error rides along as cause for the webhook
871
+ * throw new Fault({ cause });
872
+ *
873
+ * // pass report: false to show the same reply without publishing to the handledException bus
874
+ * // throw new Fault({ cause, report: false });
875
+ * }
876
+ * ```
877
+ */
878
+ var Fault = class extends Notice {
879
+ constructor(options) {
880
+ super("A fault occurred", options?.cause === void 0 ? void 0 : { cause: options.cause });
881
+ this.report = options?.report ?? true;
882
+ }
883
+ render(ctx) {
884
+ const contact = ctx.developerUsername ?? "the developer";
885
+ return { components: [new NoticeCard(`Something went wrong. Please reach out to ${contact} with a way to reproduce the error and the following:\n### UUID: \`${ctx.uuid}\``, "Error").component] };
906
886
  }
907
887
  };
908
888
 
@@ -938,100 +918,6 @@ function rollbackCommits(ctx, mark) {
938
918
  if (queue && queue.length > mark) queue.length = mark;
939
919
  }
940
920
 
941
- //#endregion
942
- //#region src/gates/catalog/options.ts
943
- function pickNotice(options, makeDefault) {
944
- return options?.notice ?? makeDefault(options?.message);
945
- }
946
-
947
- //#endregion
948
- //#region src/permissions/bits.ts
949
- const PermissionNames = new Map(Object.entries(PermissionFlagsBits).map(([key, bit]) => [bit, prettify(key)]));
950
- const ADMINISTRATOR = PermissionFlagsBits.Administrator;
951
- function nameOf(bit) {
952
- return PermissionNames.get(bit) ?? String(bit);
953
- }
954
- function holds(held, bit) {
955
- return (held & ADMINISTRATOR) === ADMINISTRATOR || (held & bit) === bit;
956
- }
957
- /** @internal */
958
- function hasAll(held, scope) {
959
- return scope.every((bit) => holds(held, bit));
960
- }
961
- /** @internal only reached once hasAll failed, so the administrator bit is absent */
962
- function missingNames(held, scope) {
963
- return scope.reduce((names, bit) => {
964
- if ((held & bit) !== bit) names.push(nameOf(bit));
965
- return names;
966
- }, []);
967
- }
968
- /** @internal */
969
- function presentNames(held, scope) {
970
- return scope.reduce((names, bit) => {
971
- if (holds(held, bit)) names.push(nameOf(bit));
972
- return names;
973
- }, []);
974
- }
975
-
976
- //#endregion
977
- //#region src/gates/catalog/permissions.ts
978
- const MEMBER_CHECK = {
979
- unresolved: "Your server member data could not be resolved. Try again.",
980
- subject: null
981
- };
982
- const BOT_CHECK = {
983
- unresolved: "The bot's permissions could not be resolved. Try again.",
984
- subject: "The bot"
985
- };
986
- function refusePermissions(held, scope, options, guildId, kind) {
987
- if (held === null) throw pickNotice(options?.notInGuild, (message) => new NotInGuild(message ?? (guildId ? kind.unresolved : void 0)));
988
- if (hasAll(held, scope)) return;
989
- throw pickNotice(options?.missing, (message) => new MissingPermissions(message, kind.subject, missingNames(held, scope)));
990
- }
991
- function RequirePermissions(scope, options) {
992
- if (options?.in === "guild") return defineGate("RequirePermissions", (ctx) => {
993
- refusePermissions(ctx.memberGuildPermissions, scope, options, ctx.guildId, MEMBER_CHECK);
994
- });
995
- return defineGate("RequirePermissions", (ctx) => {
996
- refusePermissions(ctx.memberPermissions, scope, options, ctx.guildId, MEMBER_CHECK);
997
- });
998
- }
999
- function RequireBotPermissions(scope, options) {
1000
- if (options?.in === "guild") return defineGate("RequireBotPermissions", (ctx) => {
1001
- refusePermissions(ctx.appGuildPermissions, scope, options, ctx.guildId, BOT_CHECK);
1002
- });
1003
- return defineGate("RequireBotPermissions", (ctx) => {
1004
- refusePermissions(ctx.appPermissions, scope, options, ctx.guildId, BOT_CHECK);
1005
- });
1006
- }
1007
- /**
1008
- * Requires the caller to hold `roleId`, read from the member's role ids. Refuses outside a guild first,
1009
- * then when the role is missing. Roles are guild-global, so there is no scope dimension.
1010
- *
1011
- * @param roleId - The role snowflake the caller must hold.
1012
- * @param options - Override each refusal, the outside-guild one with `notInGuild` and the missing-role one with `missingRole`.
1013
- *
1014
- * @see the `@Gated` decorator from your transport package
1015
- *
1016
- * @example
1017
- * ```ts
1018
- * \@Gated(RequireRole('123456789012345678'))
1019
- * \@SlashRoute('vip')
1020
- * class VipHandler extends SlashHandler<'vip'> {
1021
- * async execute() {
1022
- * // ...
1023
- * }
1024
- * }
1025
- * ```
1026
- */
1027
- function RequireRole(roleId, options) {
1028
- return defineGate("RequireRole", (ctx) => {
1029
- if (!ctx.guildId) throw pickNotice(options?.notInGuild, (message) => new NotInGuild(message));
1030
- if (ctx.memberRoleIds.includes(roleId)) return;
1031
- throw pickNotice(options?.missingRole, (message) => new MissingRole(message, roleId));
1032
- });
1033
- }
1034
-
1035
921
  //#endregion
1036
922
  //#region src/stops/Silence.ts
1037
923
  /**
@@ -1092,5 +978,5 @@ function pageCursor(prefix) {
1092
978
  }
1093
979
 
1094
980
  //#endregion
1095
- export { commandKey as $, serializeReply as A, contextMenuRouteOf as B, NotAllowed as C, OnCooldown as D, NotOwner as E, AckTrace as F, decodeComponentRoute as G, storeComponentRoute as H, checkAckLegality as I, CommandInjector as J, ConfigGuilds as K, sendTarget as L, attemptWrite as M, publishResponse as N, defineEffectGate as O, reportedWrite as P, warnLinks as Q, RegisterInteractionMiddleware as R, NeedsAny as S, NotInGuild as T, storeInteractionRoute as U, interactionRoutesOf as V, ComponentDefsKey as W, ContextMenus as X, Commands as Y, installLinks as Z, runCommits as _, RequireBotPermissions as a, guardedAccessor as at, MissingPermissions as b, PermissionNames as c, globalFirst as ct, presentNames as d, contextMenuLeaves as dt, commandRefOf as et, pickNotice as f, NoticeCard as ft, runCheck as g, rollbackCommits as h, Silence as i, clearStore as it, translateSerializationError as j, defineGate as k, hasAll as l, scopeIdsOf as lt, markCommits as m, pageCursor as n, linkCommands as nt, RequirePermissions as o, GLOBAL_ID as ot, discardCommits as p, Notice as pt, RegisterCommand as q, ResolvedEmoji as r, accessorStore as rt, RequireRole as s, commandsRoute as st, PAGE_MAX as t, indexById as tt, missingNames as u, skippedNote as ut, GateNotice as v, NotInDm as w, MissingRole as x, HasDangerousPermissions as y, interactionMiddlewareMetaOf as z };
1096
- //# sourceMappingURL=subscribers-D4_HZcgw.mjs.map
981
+ export { GLOBAL_ID as $, RegisterInteractionMiddleware as A, RegisterCommand as B, attemptWrite as C, AckTrace as D, lazyLogger as E, storeComponentRoute as F, warnLinks as G, Commands as H, storeInteractionRoute as I, indexById as J, commandKey as K, ComponentDefsKey as L, contextMenuRouteOf as M, interactionRoutesOf as N, checkAckLegality as O, routeDecoratorOf as P, guardedAccessor as Q, decodeComponentRoute as R, translateSerializationError as S, reportedWrite as T, ContextMenus as U, CommandInjector as V, installLinks as W, accessorStore as X, linkCommands as Y, clearStore as Z, NotInGuild as _, discardCommits as a, Notice as at, PermissionsUnresolved as b, runCheck as c, HasPresentPermissions as d, commandsRoute as et, MissingPermissions as f, NotInDm as g, NotAllowed as h, Silence as i, contextMenuLeaves as it, interactionMiddlewareMetaOf as j, sendTarget as k, runCommits as l, NeedsAny as m, pageCursor as n, scopeIdsOf as nt, markCommits as o, NoticeCard as ot, MissingRole as p, commandRefOf as q, ResolvedEmoji as r, skippedNote as rt, rollbackCommits as s, PAGE_MAX as t, globalFirst as tt, Fault as u, NotOwner as v, publishResponse as w, serializeReply as x, OnCooldown as y, ConfigGuilds as z };
982
+ //# sourceMappingURL=subscribers-CGuVjbrg.mjs.map