@wolfstar/http-framework 6.2.2 → 6.3.0-next-20261007181329

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
@@ -35,19 +35,29 @@ let Events = /* @__PURE__ */ function(Events) {
35
35
  Events["CommandNameMissing"] = "commandNameMissing";
36
36
  Events["CommandNameUnknown"] = "commandNameUnknown";
37
37
  Events["CommandMethodUnknown"] = "commandMethodUnknown";
38
+ Events["PreChatInputCommandRun"] = "preChatInputCommandRun";
39
+ Events["PreContextMenuCommandRun"] = "preContextMenuCommandRun";
40
+ Events["ChatInputCommandAccepted"] = "chatInputCommandAccepted";
41
+ Events["ContextMenuCommandAccepted"] = "contextMenuCommandAccepted";
38
42
  Events["CommandRun"] = "commandRun";
39
43
  Events["CommandSuccess"] = "commandSuccess";
40
44
  Events["CommandError"] = "commandError";
45
+ Events["ChatInputCommandDenied"] = "chatInputCommandDenied";
46
+ Events["ContextMenuCommandDenied"] = "contextMenuCommandDenied";
41
47
  Events["CommandFinish"] = "commandFinish";
48
+ Events["AutocompleteAccepted"] = "autocompleteAccepted";
42
49
  Events["AutocompleteRun"] = "autocompleteRun";
43
50
  Events["AutocompleteSuccess"] = "autocompleteSuccess";
44
51
  Events["AutocompleteError"] = "autocompleteError";
52
+ Events["AutocompleteDenied"] = "autocompleteDenied";
45
53
  Events["AutocompleteFinish"] = "autocompleteFinish";
46
54
  Events["InteractionHandlerNameInvalid"] = "interactionHandlerNameInvalid";
47
55
  Events["InteractionHandlerNameUnknown"] = "interactionHandlerNameUnknown";
56
+ Events["InteractionHandlerAccepted"] = "interactionHandlerAccepted";
48
57
  Events["InteractionHandlerRun"] = "interactionHandlerRun";
49
58
  Events["InteractionHandlerSuccess"] = "interactionHandlerSuccess";
50
59
  Events["InteractionHandlerError"] = "interactionHandlerError";
60
+ Events["InteractionHandlerDenied"] = "interactionHandlerDenied";
51
61
  Events["InteractionHandlerFinish"] = "interactionHandlerFinish";
52
62
  Events["HmrStart"] = "hmrStart";
53
63
  Events["HmrStop"] = "hmrStop";
@@ -884,6 +894,62 @@ function _useLegacy(plugin) {
884
894
  }
885
895
  }
886
896
 
897
+ //#endregion
898
+ //#region src/lib/errors/UserError.ts
899
+ /**
900
+ * The UserError class to be thrown and emitted by the pieces of the framework.
901
+ *
902
+ * @remarks
903
+ * This class is the root of every framework-thrown error, allowing consumers to distinguish
904
+ * errors that are meant to be shown to the user from unexpected, internal ones.
905
+ *
906
+ * When a command, an autocomplete handler, or an interaction handler throws a `UserError` (or any subclass), the
907
+ * client emits the matching `*Denied` event ({@link Events.ChatInputCommandDenied}, {@link Events.ContextMenuCommandDenied},
908
+ * {@link Events.AutocompleteDenied}, or {@link Events.InteractionHandlerDenied}) instead of the `*Error` one, so listeners
909
+ * can reply to the user without reporting an expected failure as a bug. Use {@link isUserError} to apply the same check.
910
+ *
911
+ * @property name This will be `'UserError'` and can be used to distinguish the type of error when any error gets thrown.
912
+ * @since 3.2.0
913
+ * @example
914
+ * ```typescript
915
+ * throw new UserError({
916
+ * identifier: Identifiers.ArgumentIntegerTooSmall,
917
+ * message: 'The number you provided is too small.',
918
+ * context: { received: 2, minimum: 3 }
919
+ * });
920
+ * ```
921
+ */
922
+ var UserError = class extends Error {
923
+ /**
924
+ * Constructs an UserError.
925
+ * @param options The UserError options
926
+ */
927
+ constructor(options) {
928
+ super(options.message);
929
+ _defineProperty(this, "identifier", void 0);
930
+ _defineProperty(this, "context", void 0);
931
+ this.identifier = options.identifier;
932
+ this.context = options.context ?? null;
933
+ }
934
+ get name() {
935
+ return "UserError";
936
+ }
937
+ };
938
+ /**
939
+ * Checks whether a value is a {@link UserError}, which is how the client tells an expected failure from an unexpected
940
+ * one.
941
+ *
942
+ * @remarks `instanceof` is tried first. A bundle that inlines the framework, or a second installed copy of it, has its
943
+ * own `UserError` class that `instanceof` does not recognise, so any `Error` with a string `identifier` and a `context`
944
+ * property is accepted too.
945
+ * @param error The value to check.
946
+ * @returns Whether the value is a `UserError`.
947
+ * @since 6.3.0
948
+ */
949
+ function isUserError(error) {
950
+ return error instanceof UserError || error instanceof Error && typeof error.identifier === "string" && "context" in error;
951
+ }
952
+
887
953
  //#endregion
888
954
  //#region src/lib/utils/decorators.ts
889
955
  /**
@@ -3078,6 +3144,8 @@ let Identifiers = /* @__PURE__ */ function(Identifiers) {
3078
3144
  Identifiers["PreconditionClientPermissionsNoPermissions"] = "preconditionClientPermissionsNoPermissions";
3079
3145
  Identifiers["PreconditionCooldown"] = "preconditionCooldown";
3080
3146
  Identifiers["PreconditionGuildIds"] = "preconditionGuildIds";
3147
+ Identifiers["PreconditionMissingChatInputHandler"] = "preconditionMissingChatInputHandler";
3148
+ Identifiers["PreconditionMissingContextMenuHandler"] = "preconditionMissingContextMenuHandler";
3081
3149
  Identifiers["PreconditionNSFW"] = "preconditionNsfw";
3082
3150
  Identifiers["PreconditionRunIn"] = "preconditionRunIn";
3083
3151
  Identifiers["PreconditionUnavailable"] = "preconditionUnavailable";
@@ -3091,41 +3159,134 @@ let Identifiers = /* @__PURE__ */ function(Identifiers) {
3091
3159
  }({});
3092
3160
 
3093
3161
  //#endregion
3094
- //#region src/lib/errors/UserError.ts
3162
+ //#region src/lib/utils/preconditions.ts
3095
3163
  /**
3096
- * The UserError class to be thrown and emitted by the pieces of the framework.
3164
+ * How the entries of an array of preconditions are run.
3097
3165
  *
3098
- * @remarks
3099
- * This class is the root of every framework-thrown error, allowing consumers to distinguish
3100
- * errors that are meant to be shown to the user from unexpected, internal ones.
3166
+ * @since 6.3.0
3167
+ */
3168
+ let PreconditionRunMode = /* @__PURE__ */ function(PreconditionRunMode) {
3169
+ /**
3170
+ * The entries are run one after the other. This is the default, and it stops as soon as the result is known.
3171
+ * @since 6.3.0
3172
+ */
3173
+ PreconditionRunMode[PreconditionRunMode["Sequential"] = 0] = "Sequential";
3174
+ /**
3175
+ * Every entry is started at once and awaited with `Promise.all`, then the results are read. It is faster when the
3176
+ * checks are slow, but none of them is skipped once another one has settled the result.
3177
+ * @since 6.3.0
3178
+ */
3179
+ PreconditionRunMode[PreconditionRunMode["Parallel"] = 1] = "Parallel";
3180
+ return PreconditionRunMode;
3181
+ }({});
3182
+ /**
3183
+ * How the results of the entries of an array of preconditions are combined.
3101
3184
  *
3102
- * @property name This will be `'UserError'` and can be used to distinguish the type of error when any error gets thrown.
3103
- * @since 3.2.0
3104
- * @example
3105
- * ```typescript
3106
- * throw new UserError({
3107
- * identifier: Identifiers.ArgumentIntegerTooSmall,
3108
- * message: 'The number you provided is too small.',
3109
- * context: { received: 2, minimum: 3 }
3110
- * });
3111
- * ```
3185
+ * @since 6.3.0
3112
3186
  */
3113
- var UserError = class extends Error {
3187
+ let PreconditionRunCondition = /* @__PURE__ */ function(PreconditionRunCondition) {
3114
3188
  /**
3115
- * Constructs an UserError.
3116
- * @param options The UserError options
3189
+ * Every entry has to pass: the first `Err` is the result.
3190
+ * @since 6.3.0
3117
3191
  */
3118
- constructor(options) {
3119
- super(options.message);
3120
- _defineProperty(this, "identifier", void 0);
3121
- _defineProperty(this, "context", void 0);
3122
- this.identifier = options.identifier;
3123
- this.context = options.context ?? null;
3124
- }
3125
- get name() {
3126
- return "UserError";
3192
+ PreconditionRunCondition[PreconditionRunCondition["And"] = 0] = "And";
3193
+ /**
3194
+ * One entry has to pass: the first `Ok` is the result, and when none does, the last `Err`.
3195
+ * @since 6.3.0
3196
+ */
3197
+ PreconditionRunCondition[PreconditionRunCondition["Or"] = 1] = "Or";
3198
+ return PreconditionRunCondition;
3199
+ }({});
3200
+ /**
3201
+ * Runs a {@link Precondition} piece for the given kind of interaction.
3202
+ *
3203
+ * @param precondition The precondition to run.
3204
+ * @param kind What is being run.
3205
+ * @param interaction The interaction being handled.
3206
+ * @param target The command or interaction handler being run.
3207
+ * @param context The context of the check.
3208
+ * @returns The result of the precondition. A chat input or context menu command is denied when the piece has no method
3209
+ * for it, an autocomplete or an interaction handler is let through.
3210
+ * @since 6.3.0
3211
+ */
3212
+ function runPrecondition(precondition, kind, interaction, target, context = {}) {
3213
+ return checkPrecondition(precondition, kind, interaction, target, context) ?? precondition.ok();
3214
+ }
3215
+ /**
3216
+ * Like {@link runPrecondition}, but `null` when the piece does not apply: it has no method for an autocomplete or an
3217
+ * interaction handler.
3218
+ */
3219
+ function checkPrecondition(precondition, kind, interaction, target, context) {
3220
+ switch (kind) {
3221
+ case "chatInput": return precondition.chatInputRun ? precondition.chatInputRun(interaction, target, context) : precondition.error({
3222
+ identifier: "preconditionMissingChatInputHandler",
3223
+ message: `The precondition "${precondition.name}" is missing a "chatInputRun" handler, but it was requested for the "${target.name}" command.`
3224
+ });
3225
+ case "contextMenu": return precondition.contextMenuRun ? precondition.contextMenuRun(interaction, target, context) : precondition.error({
3226
+ identifier: "preconditionMissingContextMenuHandler",
3227
+ message: `The precondition "${precondition.name}" is missing a "contextMenuRun" handler, but it was requested for the "${target.name}" command.`
3228
+ });
3229
+ case "autocomplete": return precondition.autocompleteRun ? precondition.autocompleteRun(interaction, target, context) : null;
3230
+ case "interactionHandler": return precondition.interactionHandlerRun ? precondition.interactionHandlerRun(interaction, target, context) : null;
3127
3231
  }
3128
- };
3232
+ }
3233
+ /**
3234
+ * Runs the preconditions of a command or an interaction handler: first the global ones of the `preconditions` store,
3235
+ * then the entries of its `preconditions` option, stopping at the first denial.
3236
+ *
3237
+ * @remarks
3238
+ * - The `preconditions` option is an array that runs with {@link PreconditionRunCondition.And}: every entry has to pass.
3239
+ * An array nested in it runs with `Or`, one nested in that with `And` again, and so on, so
3240
+ * `['Connect', ['Moderator', ['DJ', 'SongAuthor']]]` is `Connect && (Moderator || (DJ && SongAuthor))`.
3241
+ * - The {@link PreconditionRunMode} is `Sequential`, or the `mode` of the array written as `{ entries, mode }`, which the
3242
+ * arrays nested in it inherit.
3243
+ * - An entry that names a precondition missing from the store denies the interaction with
3244
+ * {@linkcode Identifiers.PreconditionUnavailable}.
3245
+ * - An entry that does not apply to the interaction, such as a function for an autocomplete or a piece with no method for
3246
+ * it, is left out of the result. An array in which no entry applies is left out as well.
3247
+ * @param target The command or interaction handler being run.
3248
+ * @param kind What is being run.
3249
+ * @param interaction The interaction being handled.
3250
+ * @returns The first `Err`, or `Result.ok()` when every precondition lets it run.
3251
+ * @since 6.3.0
3252
+ */
3253
+ async function runPreconditions(target, kind, interaction) {
3254
+ const global = await container$1.stores.get("preconditions").run(kind, interaction, target);
3255
+ if (global.isErr()) return global;
3256
+ return await runArray(target.options.preconditions ?? [], 0, 0, kind, interaction, target) ?? Result.ok();
3257
+ }
3258
+ async function runArray(array, condition, inheritedMode, kind, interaction, target) {
3259
+ const entries = Array.isArray(array) ? array : array.entries;
3260
+ const mode = Array.isArray(array) ? inheritedMode : array.mode;
3261
+ const nested = condition === 0 ? 1 : 0;
3262
+ const run = (entry) => isSingle(entry) ? runSingle(entry, kind, interaction, target) : runArray(entry, nested, mode, kind, interaction, target);
3263
+ const outcomes = mode === 1 ? await Promise.all(entries.map(run)) : null;
3264
+ let applied = false;
3265
+ let error = null;
3266
+ for (const [index, entry] of entries.entries()) {
3267
+ const outcome = outcomes ? outcomes[index] : await run(entry);
3268
+ if (outcome === null) continue;
3269
+ applied = true;
3270
+ if (condition === 0) {
3271
+ if (outcome.isErr()) return outcome;
3272
+ } else if (outcome.isOk()) return outcome;
3273
+ else error = outcome;
3274
+ }
3275
+ return error ?? (applied ? Result.ok() : null);
3276
+ }
3277
+ function isSingle(entry) {
3278
+ return typeof entry === "string" || typeof entry === "function" || !Array.isArray(entry) && "name" in entry;
3279
+ }
3280
+ async function runSingle(entry, kind, interaction, target) {
3281
+ if (typeof entry === "function") return kind === "autocomplete" ? null : entry(interaction, target);
3282
+ const name = typeof entry === "string" ? entry : entry.name;
3283
+ const precondition = container$1.stores.get("preconditions").get(name);
3284
+ if (!precondition) return Result.err(new UserError({
3285
+ identifier: "preconditionUnavailable",
3286
+ message: `The precondition "${name}" is not available.`
3287
+ }));
3288
+ return checkPrecondition(precondition, kind, interaction, target, typeof entry === "string" ? {} : entry.context ?? {});
3289
+ }
3129
3290
 
3130
3291
  //#endregion
3131
3292
  //#region src/lib/errors/ChatInputRouterError.ts
@@ -3644,8 +3805,26 @@ var CommandStore = class extends Store$1 {
3644
3805
  response.statusCode = 501;
3645
3806
  return response.end(ErrorMessages.UnknownCommandHandler);
3646
3807
  }
3808
+ const kind = interaction.data.type === ApplicationCommandType.ChatInput ? "chatInput" : "contextMenu";
3809
+ if (kind === "chatInput") container$1.client.emit("preChatInputCommandRun", context);
3810
+ else container$1.client.emit("preContextMenuCommandRun", context);
3811
+ const checked = await Result.fromAsync(async () => {
3812
+ const commandInteraction = makeInteraction(response, interaction);
3813
+ const preconditions = await runPreconditions(command, kind, commandInteraction);
3814
+ if (preconditions.isErr()) throw preconditions.unwrapErr();
3815
+ return commandInteraction;
3816
+ });
3817
+ if (checked.isErr()) {
3818
+ const error = checked.unwrapErr();
3819
+ _assertClassBrand(_CommandStore_brand, this, _emitCommandFailure).call(this, error, context);
3820
+ handleError(response, error);
3821
+ container$1.client.emit("commandFinish", context);
3822
+ return response;
3823
+ }
3824
+ if (kind === "chatInput") container$1.client.emit("chatInputCommandAccepted", context);
3825
+ else container$1.client.emit("contextMenuCommandAccepted", context);
3647
3826
  container$1.client.emit("commandRun", context);
3648
- (await Result.fromAsync(() => _assertClassBrand(_CommandStore_brand, this, _runCommandMethod).call(this, command, method, makeInteraction(response, interaction)))).inspect((value) => container$1.client.emit("commandSuccess", context, value)).inspectErr((error) => (container$1.client.emit("commandError", error, context), handleError(response, error)));
3827
+ (await Result.fromAsync(() => _assertClassBrand(_CommandStore_brand, this, _runCommandMethod).call(this, command, method, checked.unwrap()))).inspect((value) => container$1.client.emit("commandSuccess", context, value)).inspectErr((error) => (_assertClassBrand(_CommandStore_brand, this, _emitCommandFailure).call(this, error, context), handleError(response, error)));
3649
3828
  container$1.client.emit("commandFinish", context);
3650
3829
  return response;
3651
3830
  }
@@ -3675,13 +3854,49 @@ var CommandStore = class extends Store$1 {
3675
3854
  response
3676
3855
  };
3677
3856
  const options = transformAutocompleteInteraction(interaction.data.resolved ?? {}, interaction.data.options);
3857
+ const checked = await Result.fromAsync(async () => {
3858
+ const autocompleteInteraction = makeInteraction(response, interaction);
3859
+ const preconditions = await runPreconditions(command, "autocomplete", autocompleteInteraction);
3860
+ if (preconditions.isErr()) throw preconditions.unwrapErr();
3861
+ return autocompleteInteraction;
3862
+ });
3863
+ if (checked.isErr()) {
3864
+ _assertClassBrand(_CommandStore_brand, this, _emitAutocompleteFailure).call(this, checked.unwrapErr(), context, response);
3865
+ container$1.client.emit("autocompleteFinish", context);
3866
+ return response;
3867
+ }
3868
+ container$1.client.emit("autocompleteAccepted", context);
3678
3869
  container$1.client.emit("autocompleteRun", context);
3679
- (await Result.fromAsync(() => command.autocompleteRun(makeInteraction(response, interaction), options))).inspect((value) => container$1.client.emit("autocompleteSuccess", context, value)).inspectErr((error) => (container$1.client.emit("autocompleteError", error, context), handleError(response, error)));
3870
+ (await Result.fromAsync(() => command.autocompleteRun(checked.unwrap(), options))).inspect((value) => container$1.client.emit("autocompleteSuccess", context, value)).inspectErr((error) => _assertClassBrand(_CommandStore_brand, this, _emitAutocompleteFailure).call(this, error, context, response));
3680
3871
  container$1.client.emit("autocompleteFinish", context);
3681
3872
  return response;
3682
3873
  }
3683
3874
  };
3684
3875
  /**
3876
+ * Emits `autocompleteDenied` for a {@link UserError} and `autocompleteError` otherwise, then replies as for any
3877
+ * other thrown error.
3878
+ *
3879
+ * @param error - The value that was thrown.
3880
+ * @param context - The context of the run.
3881
+ * @param response - The server response object.
3882
+ */
3883
+ function _emitAutocompleteFailure(error, context, response) {
3884
+ if (isUserError(error)) container$1.client.emit("autocompleteDenied", error, context);
3885
+ else container$1.client.emit("autocompleteError", error, context);
3886
+ handleError(response, error);
3887
+ }
3888
+ /**
3889
+ * Emits the event matching a failed command run: a `*Denied` one for a {@link UserError}, `commandError` otherwise.
3890
+ *
3891
+ * @param error - The value the command threw.
3892
+ * @param context - The context of the run.
3893
+ */
3894
+ function _emitCommandFailure(error, context) {
3895
+ if (!isUserError(error)) container$1.client.emit("commandError", error, context);
3896
+ else if (context.interaction.data.type === ApplicationCommandType.ChatInput) container$1.client.emit("chatInputCommandDenied", error, context);
3897
+ else container$1.client.emit("contextMenuCommandDenied", error, context);
3898
+ }
3899
+ /**
3685
3900
  * Executes a command method on a command object.
3686
3901
  *
3687
3902
  * @since 1.0.0
@@ -3737,9 +3952,11 @@ var InteractionHandler = class extends Piece$1 {
3737
3952
 
3738
3953
  //#endregion
3739
3954
  //#region src/lib/structures/InteractionHandlerStore.ts
3955
+ var _InteractionHandlerStore_brand = /* @__PURE__ */ new WeakSet();
3740
3956
  var InteractionHandlerStore = class extends Store$1 {
3741
3957
  constructor() {
3742
3958
  super(InteractionHandler, { name: "interaction-handlers" });
3959
+ _classPrivateMethodInitSpec(this, _InteractionHandlerStore_brand);
3743
3960
  }
3744
3961
  async runHandler(response, interaction) {
3745
3962
  const parsed = container$1.idParser.run(interaction.data.custom_id);
@@ -3759,12 +3976,37 @@ var InteractionHandlerStore = class extends Store$1 {
3759
3976
  interaction,
3760
3977
  response
3761
3978
  };
3979
+ const checked = await Result.fromAsync(async () => {
3980
+ const handlerInteraction = makeInteraction(response, interaction);
3981
+ const preconditions = await runPreconditions(handler, "interactionHandler", handlerInteraction);
3982
+ if (preconditions.isErr()) throw preconditions.unwrapErr();
3983
+ return handlerInteraction;
3984
+ });
3985
+ if (checked.isErr()) {
3986
+ _assertClassBrand(_InteractionHandlerStore_brand, this, _emitFailure).call(this, checked.unwrapErr(), context, response);
3987
+ container$1.client.emit("interactionHandlerFinish", context);
3988
+ return response;
3989
+ }
3990
+ container$1.client.emit("interactionHandlerAccepted", context);
3762
3991
  container$1.client.emit("interactionHandlerRun", context);
3763
- (await Result.fromAsync(() => handler.run(makeInteraction(response, interaction), parsed.content))).inspect((value) => container$1.client.emit("interactionHandlerSuccess", context, value)).inspectErr((error) => (container$1.client.emit("interactionHandlerError", error, context), handleError(response, error)));
3992
+ (await Result.fromAsync(() => handler.run(checked.unwrap(), parsed.content))).inspect((value) => container$1.client.emit("interactionHandlerSuccess", context, value)).inspectErr((error) => _assertClassBrand(_InteractionHandlerStore_brand, this, _emitFailure).call(this, error, context, response));
3764
3993
  container$1.client.emit("interactionHandlerFinish", context);
3765
3994
  return response;
3766
3995
  }
3767
3996
  };
3997
+ /**
3998
+ * Emits `interactionHandlerDenied` for a {@link UserError} and `interactionHandlerError` otherwise, then replies as
3999
+ * for any other thrown error.
4000
+ *
4001
+ * @param error - The value that was thrown.
4002
+ * @param context - The context of the run.
4003
+ * @param response - The server response object.
4004
+ */
4005
+ function _emitFailure(error, context, response) {
4006
+ if (isUserError(error)) container$1.client.emit("interactionHandlerDenied", error, context);
4007
+ else container$1.client.emit("interactionHandlerError", error, context);
4008
+ handleError(response, error);
4009
+ }
3768
4010
 
3769
4011
  //#endregion
3770
4012
  //#region src/lib/structures/Listener.ts
@@ -3829,6 +4071,152 @@ var ListenerStore = class extends Store$1 {
3829
4071
  }
3830
4072
  };
3831
4073
 
4074
+ //#endregion
4075
+ //#region src/lib/errors/PreconditionError.ts
4076
+ /**
4077
+ * Errors thrown by preconditions, that is, any check that runs before a command or an interaction
4078
+ * handler is executed, such as the guild restrictions applied by
4079
+ * {@link RestrictGuildIds}.
4080
+ *
4081
+ * @remarks Being a {@link UserError}, it is emitted as a `*Denied` event when thrown from a command, an autocomplete
4082
+ * handler, or an interaction handler, and not as `commandError`. The framework has no precondition store: the
4083
+ * decorators of `@wolfstar/decorators` are what throws it.
4084
+ *
4085
+ * @property name This will be `'PreconditionError'` and can be used to distinguish the type of error when any error gets thrown.
4086
+ * @since 3.2.0
4087
+ * @example
4088
+ * ```typescript
4089
+ * throw new PreconditionError({
4090
+ * precondition: 'GuildIds',
4091
+ * identifier: Identifiers.PreconditionGuildIds,
4092
+ * message: 'This command can only be used in specific guilds.',
4093
+ * context: { guildIds: ['737141877803057244'] }
4094
+ * });
4095
+ * ```
4096
+ */
4097
+ var PreconditionError = class extends UserError {
4098
+ constructor(options) {
4099
+ super({
4100
+ ...options,
4101
+ identifier: options.identifier ?? options.precondition
4102
+ });
4103
+ _defineProperty(this, "precondition", void 0);
4104
+ this.precondition = options.precondition;
4105
+ }
4106
+ get name() {
4107
+ return "PreconditionError";
4108
+ }
4109
+ };
4110
+
4111
+ //#endregion
4112
+ //#region src/lib/structures/Precondition.ts
4113
+ /**
4114
+ * A check that runs before a command method does, loaded from the `preconditions` directory into the
4115
+ * `preconditions` store.
4116
+ *
4117
+ * @remarks A precondition with a `position` is global: it runs, in ascending order of `position`, before the
4118
+ * preconditions of every chat input and context menu command, and of every autocomplete and interaction handler that
4119
+ * it has a method for. Any other one runs only for the commands that list its
4120
+ * name in the `preconditions` option. The method it needs depends on the command, and a precondition that is asked to
4121
+ * run for a kind of command it has no method for denies the command with
4122
+ * {@linkcode Identifiers.PreconditionMissingChatInputHandler} or
4123
+ * {@linkcode Identifiers.PreconditionMissingContextMenuHandler}.
4124
+ * @since 6.3.0
4125
+ * @example
4126
+ * ```typescript
4127
+ * import { Precondition } from '@wolfstar/http-framework';
4128
+ *
4129
+ * export class UserPrecondition extends Precondition {
4130
+ * public override chatInputRun(interaction: Precondition.ChatInputInteraction) {
4131
+ * return interaction.user.id === process.env.OWNER_ID ? this.ok() : this.error({ message: 'Only the owner can use this command.' });
4132
+ * }
4133
+ * }
4134
+ * ```
4135
+ */
4136
+ var Precondition = class extends Piece$1 {
4137
+ constructor(context, options = {}) {
4138
+ super(context, options);
4139
+ _defineProperty(this, "position", void 0);
4140
+ this.position = options.position ?? null;
4141
+ }
4142
+ /**
4143
+ * Lets the command run.
4144
+ * @since 6.3.0
4145
+ */
4146
+ ok() {
4147
+ return Result.ok();
4148
+ }
4149
+ /**
4150
+ * Denies the command with a {@link PreconditionError} whose `precondition` is the name of this piece.
4151
+ *
4152
+ * @param options The message, identifier and context of the error.
4153
+ * @since 6.3.0
4154
+ */
4155
+ error(options = {}) {
4156
+ return Result.err(new PreconditionError({
4157
+ precondition: this.name,
4158
+ ...options
4159
+ }));
4160
+ }
4161
+ };
4162
+ /**
4163
+ * A {@link Precondition} that has to implement the check for every kind of command.
4164
+ *
4165
+ * @since 6.3.0
4166
+ */
4167
+ var AllFlowsPrecondition = class extends Precondition {};
4168
+
4169
+ //#endregion
4170
+ //#region src/lib/structures/PreconditionStore.ts
4171
+ var _globalPreconditions = /* @__PURE__ */ new WeakMap();
4172
+ var _PreconditionStore_brand = /* @__PURE__ */ new WeakSet();
4173
+ var PreconditionStore = class extends Store$1 {
4174
+ constructor() {
4175
+ super(Precondition, { name: "preconditions" });
4176
+ _classPrivateMethodInitSpec(this, _PreconditionStore_brand);
4177
+ _classPrivateFieldInitSpec(this, _globalPreconditions, []);
4178
+ }
4179
+ /**
4180
+ * Runs the global preconditions, the ones with a `position`, in ascending order of it, stopping at the first one
4181
+ * that denies the interaction.
4182
+ *
4183
+ * @since 6.3.0
4184
+ * @param kind What is being run.
4185
+ * @param interaction The interaction being handled.
4186
+ * @param target The command or interaction handler being run.
4187
+ * @param context The context of the checks.
4188
+ * @returns The first `Err`, or `Result.ok()` when every global precondition lets the command run.
4189
+ */
4190
+ async run(kind, interaction, target, context = {}) {
4191
+ for (const precondition of _classPrivateFieldGet2(_globalPreconditions, this)) {
4192
+ const result = await runPrecondition(precondition, kind, interaction, target, context);
4193
+ if (result.isErr()) return result;
4194
+ }
4195
+ return Result.ok();
4196
+ }
4197
+ set(key, value) {
4198
+ _assertClassBrand(_PreconditionStore_brand, this, _removeGlobal).call(this, key);
4199
+ if (value.position !== null) {
4200
+ const index = _classPrivateFieldGet2(_globalPreconditions, this).findIndex((precondition) => precondition.position >= value.position);
4201
+ if (index === -1) _classPrivateFieldGet2(_globalPreconditions, this).push(value);
4202
+ else _classPrivateFieldGet2(_globalPreconditions, this).splice(index, 0, value);
4203
+ }
4204
+ return super.set(key, value);
4205
+ }
4206
+ delete(key) {
4207
+ _assertClassBrand(_PreconditionStore_brand, this, _removeGlobal).call(this, key);
4208
+ return super.delete(key);
4209
+ }
4210
+ clear() {
4211
+ _classPrivateFieldGet2(_globalPreconditions, this).length = 0;
4212
+ return super.clear();
4213
+ }
4214
+ };
4215
+ function _removeGlobal(key) {
4216
+ const index = _classPrivateFieldGet2(_globalPreconditions, this).findIndex((precondition) => precondition.name === key);
4217
+ if (index !== -1) _classPrivateFieldGet2(_globalPreconditions, this).splice(index, 1);
4218
+ }
4219
+
3832
4220
  //#endregion
3833
4221
  //#region src/lib/utils/fetch-bridge.ts
3834
4222
  function toIncomingMessage(request) {
@@ -4029,6 +4417,7 @@ async function getSafeTextBody(request) {
4029
4417
  container$1.stores.register(new CommandStore());
4030
4418
  container$1.stores.register(new InteractionHandlerStore());
4031
4419
  container$1.stores.register(new ListenerStore());
4420
+ container$1.stores.register(new PreconditionStore());
4032
4421
  container$1.logger ??= new Logger();
4033
4422
  var _discordPublicKey = /* @__PURE__ */ new WeakMap();
4034
4423
  var _fetchKey = /* @__PURE__ */ new WeakMap();
@@ -4218,6 +4607,10 @@ _defineProperty(Client, "plugins", new PluginManager());
4218
4607
  /**
4219
4608
  * Errors thrown while resolving the options (arguments) of an interaction.
4220
4609
  *
4610
+ * @remarks The framework never throws this error by itself: Discord validates the type and the bounds of the options
4611
+ * before sending the interaction. It is meant to be thrown from a command that rejects a value, and, being a
4612
+ * {@link UserError}, it is emitted as a `*Denied` event.
4613
+ *
4221
4614
  * @property name This will be `'ArgumentError'` and can be used to distinguish the type of error when any error gets thrown.
4222
4615
  * @since 3.2.0
4223
4616
  * @example
@@ -4249,39 +4642,6 @@ var ArgumentError = class extends UserError {
4249
4642
  }
4250
4643
  };
4251
4644
 
4252
- //#endregion
4253
- //#region src/lib/errors/PreconditionError.ts
4254
- /**
4255
- * Errors thrown by preconditions, that is, any check that runs before a command or an interaction
4256
- * handler is executed, such as the guild restrictions applied by
4257
- * {@link RestrictGuildIds}.
4258
- *
4259
- * @property name This will be `'PreconditionError'` and can be used to distinguish the type of error when any error gets thrown.
4260
- * @since 3.2.0
4261
- * @example
4262
- * ```typescript
4263
- * throw new PreconditionError({
4264
- * precondition: 'GuildIds',
4265
- * identifier: Identifiers.PreconditionGuildIds,
4266
- * message: 'This command can only be used in specific guilds.',
4267
- * context: { guildIds: ['737141877803057244'] }
4268
- * });
4269
- * ```
4270
- */
4271
- var PreconditionError = class extends UserError {
4272
- constructor(options) {
4273
- super({
4274
- ...options,
4275
- identifier: options.identifier ?? options.precondition
4276
- });
4277
- _defineProperty(this, "precondition", void 0);
4278
- this.precondition = options.precondition;
4279
- }
4280
- get name() {
4281
- return "PreconditionError";
4282
- }
4283
- };
4284
-
4285
4645
  //#endregion
4286
4646
  //#region src/lib/plugins/Plugin.ts
4287
4647
  /**
@@ -4348,5 +4708,5 @@ function toPermissionNames(bits) {
4348
4708
  }
4349
4709
 
4350
4710
  //#endregion
4351
- export { AliasPiece, AliasStore, ApplicationCommandRegistry, ApplicationCommandRegistryEntry, ArgumentError, AutocompleteInteraction, BaseInteraction, ChatInputCommandInteraction, ChatInputRouterError, ChatInputRouterErrors, Client, Command, CommandInteraction, CommandLoaderStrategy, CommandRegistry, CommandRouter, CommandStore, CommandStoreRouter, Events, HotModuleReloader, HttpCodes, Identifiers, InteractionHandler, InteractionHandlerStore, Listener, ListenerLoaderStrategy, ListenerStore, LoaderError, LogLevel, Logger, Message, MessageComponentButtonInteraction, MessageComponentChannelSelectInteraction, MessageComponentInteraction, MessageComponentMentionableSelectInteraction, MessageComponentRoleSelectInteraction, MessageComponentStringSelectInteraction as MessageComponentSelectMenuInteraction, MessageComponentStringSelectInteraction, MessageComponentUserSelectInteraction, MessageContextMenuCommandInteraction, MissingExportsError, ModalSubmitInteraction, PartialMessage, Piece, Plugin, PluginHook, PluginHookError, PluginManager, PreconditionError, RegisterCommand, RegisterMessageCommand, RegisterSubcommand, RegisterSubcommandGroup, RegisterUserCommand, RestrictGuildIds, Store, StoreRegistry, StringIdParser, UserContextMenuCommandInteraction, UserError, applicationCommandRegistry, container, definePlugin, extractTopLevelOptions, getMissingPermissions, makeInteraction, postInitialization, postListen, preGenericsInitialization, preInitialization, preLoad, resolvePermissions, restrictedGuildIdRegistry, toPermissionNames, toPluginEntries, transformAutocompleteInteraction, transformInteraction, transformMessageInteraction, transformUserInteraction };
4711
+ export { AliasPiece, AliasStore, AllFlowsPrecondition, ApplicationCommandRegistry, ApplicationCommandRegistryEntry, ArgumentError, AutocompleteInteraction, BaseInteraction, ChatInputCommandInteraction, ChatInputRouterError, ChatInputRouterErrors, Client, Command, CommandInteraction, CommandLoaderStrategy, CommandRegistry, CommandRouter, CommandStore, CommandStoreRouter, Events, HotModuleReloader, HttpCodes, Identifiers, InteractionHandler, InteractionHandlerStore, Listener, ListenerLoaderStrategy, ListenerStore, LoaderError, LogLevel, Logger, Message, MessageComponentButtonInteraction, MessageComponentChannelSelectInteraction, MessageComponentInteraction, MessageComponentMentionableSelectInteraction, MessageComponentRoleSelectInteraction, MessageComponentStringSelectInteraction as MessageComponentSelectMenuInteraction, MessageComponentStringSelectInteraction, MessageComponentUserSelectInteraction, MessageContextMenuCommandInteraction, MissingExportsError, ModalSubmitInteraction, PartialMessage, Piece, Plugin, PluginHook, PluginHookError, PluginManager, Precondition, PreconditionError, PreconditionRunCondition, PreconditionRunMode, PreconditionStore, RegisterCommand, RegisterMessageCommand, RegisterSubcommand, RegisterSubcommandGroup, RegisterUserCommand, RestrictGuildIds, Store, StoreRegistry, StringIdParser, UserContextMenuCommandInteraction, UserError, applicationCommandRegistry, container, definePlugin, extractTopLevelOptions, getMissingPermissions, isUserError, makeInteraction, postInitialization, postListen, preGenericsInitialization, preInitialization, preLoad, resolvePermissions, restrictedGuildIdRegistry, runPrecondition, runPreconditions, toPermissionNames, toPluginEntries, transformAutocompleteInteraction, transformInteraction, transformMessageInteraction, transformUserInteraction };
4352
4712
  //# sourceMappingURL=index.js.map