@seedcord/core 0.2.0-next.0 → 0.2.1-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{Plugin-Cl5P7-PO.d.mts → Plugin-B6iRzm3g.d.mts} +11 -7
- package/dist/Plugin-Bkeqcjy6.mjs.map +1 -1
- package/dist/{cursor-__0_F4rW.d.mts → cursor-0Dpi07Sj.d.mts} +8 -8
- package/dist/{cursor-B07ArwDz.mjs → cursor-BRyCNqRV.mjs} +4 -4
- package/dist/{cursor-B07ArwDz.mjs.map → cursor-BRyCNqRV.mjs.map} +1 -1
- package/dist/{index-TYnQ-ztr.d.mts → index-uBwh8r7x.d.mts} +2 -2
- package/dist/index.d.mts +7 -7
- package/dist/index.mjs +6 -6
- package/dist/index.mjs.map +1 -1
- package/dist/internal.index.d.mts +2 -2
- package/dist/internal.index.mjs +1 -1
- package/dist/node-internal.index.d.mts +2 -2
- package/dist/plugin.index.d.mts +1 -1
- package/package.json +9 -9
|
@@ -389,6 +389,10 @@ interface CoreBase {
|
|
|
389
389
|
readonly bus: Bus;
|
|
390
390
|
}
|
|
391
391
|
//#endregion
|
|
392
|
+
//#region src/plugin/brands.d.ts
|
|
393
|
+
declare const TransportBrand: unique symbol;
|
|
394
|
+
declare const RuntimeBrand: unique symbol;
|
|
395
|
+
//#endregion
|
|
392
396
|
//#region src/lifecycle/phases.d.ts
|
|
393
397
|
/**
|
|
394
398
|
* Startup phases, in run order.
|
|
@@ -476,10 +480,10 @@ type EdgePluginsUnsupported = Record<'an edge bot takes no plugins until edge su
|
|
|
476
480
|
/** @internal */
|
|
477
481
|
type ChannelKeyAssert<Key extends string> = Key extends FrameworkChannel ? `'${Key}' is a channel the framework logs on. Pick another plugin key.` : Key;
|
|
478
482
|
type BrandTransport<Plug> = Plug extends {
|
|
479
|
-
readonly
|
|
483
|
+
readonly [TransportBrand]?: infer T extends string;
|
|
480
484
|
} ? T : 'any';
|
|
481
485
|
type BrandRuntime<Plug> = Plug extends {
|
|
482
|
-
readonly
|
|
486
|
+
readonly [RuntimeBrand]?: infer R extends string;
|
|
483
487
|
} ? R : 'any';
|
|
484
488
|
/** @internal */
|
|
485
489
|
type TransportAssert<Plug, BotT extends Transport> = BrandTransport<Plug> extends 'any' | BotT ? unknown : TransportMismatch<BrandTransport<Plug>, BotT>;
|
|
@@ -503,10 +507,10 @@ declare const loggerSlot: unique symbol;
|
|
|
503
507
|
*/
|
|
504
508
|
declare abstract class Plugin<Opts extends PluginOptions = {}, TCore extends CoreBase = CoreBase> implements Initializeable, HmrAware {
|
|
505
509
|
private readonly host;
|
|
506
|
-
/** @internal
|
|
507
|
-
readonly
|
|
508
|
-
/** @internal
|
|
509
|
-
readonly
|
|
510
|
+
/** @internal */
|
|
511
|
+
readonly [TransportBrand]?: TransportOf<Opts>;
|
|
512
|
+
/** @internal */
|
|
513
|
+
readonly [RuntimeBrand]?: RuntimeOf<Opts>;
|
|
510
514
|
/** @internal */
|
|
511
515
|
readonly [resolvedSpecSlot]: ResolvedPluginLifecycleSpec;
|
|
512
516
|
/** @internal */
|
|
@@ -549,4 +553,4 @@ type CoreParamTooNarrow = Record<'this plugin constructor must take CoreBase as
|
|
|
549
553
|
type CoreParamAssert<Ctor extends PluginCtor> = CoreBase extends ConstructorParameters<Ctor>[0] ? unknown : CoreParamTooNarrow;
|
|
550
554
|
//#endregion
|
|
551
555
|
export { reportedWrite as A, InteractionMetadataKey as B, DispatchOutcome as C, Subscriptions as D, SubscriptionKey as E, AckTrace as F, WebhookUrlMetadataKey as G, InteractionRoutes as H, PublishDefault as I, CommandMetadataKey as L, ReplyMethod as M, checkAckLegality as N, Notice as O, sendTarget as P, EventMetadataKey as R, DefaultSubscriptions as S, SubscriptionData as T, MiddlewareMetadataKey as U, InteractionRouteKeys as V, SubscribeMetadataKey as W, Bus as _, PluginCtor as a, busLoggerOf as b, PluginOptions as c, Transport as d, TransportAssert as f, CoreBase as g, StartupPhase as h, PluginArgs as i, AckState as j, ReplyTelemetry as k, Runtime as l, ShutdownPhase as m, Initializeable as n, PluginLike as o, PluginLifecycleSpec as p, Plugin as r, ChannelKeyAssert as s, CoreParamAssert as t, RuntimeAssert as u, StoredSubscriberCtor as v, FaultSource as w, Subscriber as x, SubscriberRegistration as y, GatedMetadataKey as z };
|
|
552
|
-
//# sourceMappingURL=Plugin-
|
|
556
|
+
//# sourceMappingURL=Plugin-B6iRzm3g.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Plugin-Bkeqcjy6.mjs","names":[],"sources":["../src/plugin/lifecycle.ts","../src/plugin/Plugin.ts"],"sourcesContent":["import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { ShutdownPhase, StartupPhase } from '#src/lifecycle/phases';\n\n/**\n * The lifecycle a plugin declares through `super(host, spec)`. Unset fields resolve to the base\n * defaults. `ready` runs at a fixed `StartupPhase.Ready`.\n */\nexport interface PluginLifecycleSpec {\n init?: { phase?: StartupPhase; timeout?: number };\n ready?: { timeout?: number };\n dispose?: { phase?: ShutdownPhase; timeout?: number };\n}\n\n/** @internal */\nexport interface ResolvedPluginLifecycleSpec {\n readonly init: { readonly phase: StartupPhase; readonly timeout: number };\n readonly ready: { readonly timeout: number };\n readonly dispose: { readonly phase: ShutdownPhase; readonly timeout: number };\n}\n\nconst DEFAULT_INIT_TIMEOUT_MS = 15_000;\nconst DEFAULT_READY_TIMEOUT_MS = 15_000;\nconst DEFAULT_DISPOSE_TIMEOUT_MS = 10_000;\n\nfunction timeoutOf(\n field: 'init' | 'ready' | 'dispose',\n declared: number | undefined,\n fallback: number,\n pluginName: string\n): number {\n if (declared === undefined) return fallback;\n if (!Number.isFinite(declared) || declared <= 0) {\n throw new SeedcordError(SeedcordErrorCode.PluginOptionsRejected, [\n pluginName,\n `lifecycle ${field}.timeout must be a positive number of milliseconds`\n ]);\n }\n return declared;\n}\n\n/** @internal */\nexport function resolveLifecycleSpec(\n spec: PluginLifecycleSpec | undefined,\n pluginName: string\n): ResolvedPluginLifecycleSpec {\n return {\n init: {\n phase: spec?.init?.phase ?? StartupPhase.Configuration,\n timeout: timeoutOf('init', spec?.init?.timeout, DEFAULT_INIT_TIMEOUT_MS, pluginName)\n },\n ready: {\n timeout: timeoutOf('ready', spec?.ready?.timeout, DEFAULT_READY_TIMEOUT_MS, pluginName)\n },\n dispose: {\n phase: spec?.dispose?.phase ?? ShutdownPhase.Disconnect,\n timeout: timeoutOf('dispose', spec?.dispose?.timeout, DEFAULT_DISPOSE_TIMEOUT_MS, pluginName)\n }\n };\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Logger } from '@seedcord/logger';\n\nimport { getDevChannel } from '#hmr/devChannel';\n\nimport { resolveLifecycleSpec } from './lifecycle';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { ResolvedPluginLifecycleSpec, PluginLifecycleSpec } from './lifecycle';\nimport type { TransportOf, PluginOptions, RuntimeOf } from './options';\nimport type { Tail, HmrAware, HmrUpdateEvent } from '@seedcord/types';\n\nexport interface Initializeable {\n init(): Promise<void>;\n}\n\n/** @internal */\nconst resolvedSpecSlot = Symbol('seedcord.plugin.spec');\n/** @internal */\nconst loggerSlot = Symbol('seedcord.plugin.logger');\n\n/**\n * Base class for Seedcord plugins. A subclass declares its options as the `Opts` type argument,\n * implements `init()`, and reads the framework surface through `this.core`.\n *\n * @typeParam Opts - The plugin's declared {@link PluginOptions}.\n * @typeParam TCore - The host type `this.core` resolves to. Each transport binds it to its own `Core`.\n */\nexport abstract class Plugin<Opts extends PluginOptions = {}, TCore extends CoreBase = CoreBase>\n implements Initializeable, HmrAware\n{\n
|
|
1
|
+
{"version":3,"file":"Plugin-Bkeqcjy6.mjs","names":[],"sources":["../src/plugin/lifecycle.ts","../src/plugin/Plugin.ts"],"sourcesContent":["import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { ShutdownPhase, StartupPhase } from '#src/lifecycle/phases';\n\n/**\n * The lifecycle a plugin declares through `super(host, spec)`. Unset fields resolve to the base\n * defaults. `ready` runs at a fixed `StartupPhase.Ready`.\n */\nexport interface PluginLifecycleSpec {\n init?: { phase?: StartupPhase; timeout?: number };\n ready?: { timeout?: number };\n dispose?: { phase?: ShutdownPhase; timeout?: number };\n}\n\n/** @internal */\nexport interface ResolvedPluginLifecycleSpec {\n readonly init: { readonly phase: StartupPhase; readonly timeout: number };\n readonly ready: { readonly timeout: number };\n readonly dispose: { readonly phase: ShutdownPhase; readonly timeout: number };\n}\n\nconst DEFAULT_INIT_TIMEOUT_MS = 15_000;\nconst DEFAULT_READY_TIMEOUT_MS = 15_000;\nconst DEFAULT_DISPOSE_TIMEOUT_MS = 10_000;\n\nfunction timeoutOf(\n field: 'init' | 'ready' | 'dispose',\n declared: number | undefined,\n fallback: number,\n pluginName: string\n): number {\n if (declared === undefined) return fallback;\n if (!Number.isFinite(declared) || declared <= 0) {\n throw new SeedcordError(SeedcordErrorCode.PluginOptionsRejected, [\n pluginName,\n `lifecycle ${field}.timeout must be a positive number of milliseconds`\n ]);\n }\n return declared;\n}\n\n/** @internal */\nexport function resolveLifecycleSpec(\n spec: PluginLifecycleSpec | undefined,\n pluginName: string\n): ResolvedPluginLifecycleSpec {\n return {\n init: {\n phase: spec?.init?.phase ?? StartupPhase.Configuration,\n timeout: timeoutOf('init', spec?.init?.timeout, DEFAULT_INIT_TIMEOUT_MS, pluginName)\n },\n ready: {\n timeout: timeoutOf('ready', spec?.ready?.timeout, DEFAULT_READY_TIMEOUT_MS, pluginName)\n },\n dispose: {\n phase: spec?.dispose?.phase ?? ShutdownPhase.Disconnect,\n timeout: timeoutOf('dispose', spec?.dispose?.timeout, DEFAULT_DISPOSE_TIMEOUT_MS, pluginName)\n }\n };\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Logger } from '@seedcord/logger';\n\nimport { getDevChannel } from '#hmr/devChannel';\n\nimport { RuntimeBrand, TransportBrand } from './brands';\nimport { resolveLifecycleSpec } from './lifecycle';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { ResolvedPluginLifecycleSpec, PluginLifecycleSpec } from './lifecycle';\nimport type { TransportOf, PluginOptions, RuntimeOf } from './options';\nimport type { Tail, HmrAware, HmrUpdateEvent } from '@seedcord/types';\n\nexport interface Initializeable {\n init(): Promise<void>;\n}\n\n/** @internal */\nconst resolvedSpecSlot = Symbol('seedcord.plugin.spec');\n/** @internal */\nconst loggerSlot = Symbol('seedcord.plugin.logger');\n\n/**\n * Base class for Seedcord plugins. A subclass declares its options as the `Opts` type argument,\n * implements `init()`, and reads the framework surface through `this.core`.\n *\n * @typeParam Opts - The plugin's declared {@link PluginOptions}.\n * @typeParam TCore - The host type `this.core` resolves to. Each transport binds it to its own `Core`.\n */\nexport abstract class Plugin<Opts extends PluginOptions = {}, TCore extends CoreBase = CoreBase>\n implements Initializeable, HmrAware\n{\n // phantom, never set at runtime.\n /** @internal */\n declare readonly [TransportBrand]?: TransportOf<Opts>;\n /** @internal */\n declare readonly [RuntimeBrand]?: RuntimeOf<Opts>;\n\n /** @internal */\n readonly [resolvedSpecSlot]: ResolvedPluginLifecycleSpec;\n /** @internal */\n readonly [loggerSlot]: Logger;\n\n /** Logs under the plugin's class name, on the channel its attach key sets. */\n protected readonly logger: Logger;\n\n // CoreBase here keeps the augmented Core out of ConstructorParameters, which attach reads\n constructor(\n private readonly host: CoreBase,\n spec?: PluginLifecycleSpec\n ) {\n this.logger = new Logger(this.constructor.name);\n this[loggerSlot] = this.logger;\n this[resolvedSpecSlot] = resolveLifecycleSpec(spec, this.constructor.name);\n }\n\n /** The host, typed to the transport whose `Plugin` base this class extends. */\n protected get core(): TCore {\n // justified: each transport binds TCore to the Core its own host satisfies\n return this.host as TCore;\n }\n\n abstract init(): Promise<void>;\n\n /**\n * Runs in the startup Ready phase, after `init()`. The gateway client is logged in by this phase,\n * and the http host binds its server in the same phase.\n */\n ready?(): Promise<void>;\n\n /** Runs during teardown, only when `init()` resolved. */\n dispose?(): Promise<void>;\n\n /**\n * Throws a `SeedcordError` that contains the plugin class name and the reason.\n *\n * @param reason - Why the options are invalid.\n */\n protected rejectOptions(reason: string): never {\n throw new SeedcordError(SeedcordErrorCode.PluginOptionsRejected, [this.constructor.name, reason]);\n }\n\n /** Override to reload plugin state on an HMR update. */\n public onHmr(_event: HmrUpdateEvent): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * Registers critical file patterns that should trigger a full restart when changed in Dev HMR.\n * @param patterns - Glob patterns relative to the project root\n */\n protected registerCriticalFiles(patterns: string[]): void {\n getDevChannel()?.send('seedcord:register-critical-files', { patterns });\n }\n}\n\n/** @internal */\nexport function resolvedLifecycleSpecOf(plugin: PluginLike): ResolvedPluginLifecycleSpec {\n return plugin[resolvedSpecSlot];\n}\n\n/** @internal */\nexport function pluginLoggerOf(plugin: PluginLike): Logger {\n return plugin[loggerSlot];\n}\n\nexport type { PluginLifecycleSpec } from './lifecycle';\nexport type { PluginOptions } from './options';\n\n// a bound of Plugin<{}> rejects every plugin that declares an option, since Plugin<A> and Plugin<B>\n// are mutually unassignable. every member here must stay Opts-independent.\n/** @internal */\nexport type PluginLike = Pick<\n Plugin,\n 'init' | 'ready' | 'dispose' | 'onHmr' | typeof resolvedSpecSlot | typeof loggerSlot\n>;\n\n// a `CoreBase` first parameter rejects a narrowing ctor on its own, and it also collapses\n// `InstanceType<Ctor>` to `PluginLike` at every attach call. CoreParamAssert checks it instead.\n/** @internal */\nexport type PluginCtor<TPlugin extends PluginLike = PluginLike> = new (...args: any[]) => TPlugin;\n\n/** @internal */\nexport type PluginArgs<Ctor extends PluginCtor> = Tail<ConstructorParameters<Ctor>>;\n\ntype CoreParamTooNarrow = Record<\n 'this plugin constructor must take CoreBase as its first parameter and read the transport Core off this.core',\n never\n>;\n\n// a narrowed first parameter fails `CoreBase extends Param`\n/** @internal */\nexport type CoreParamAssert<Ctor extends PluginCtor> = CoreBase extends ConstructorParameters<Ctor>[0]\n ? unknown\n : CoreParamTooNarrow;\n"],"mappings":";;;;;;;AAsBA,MAAM,0BAA0B;AAChC,MAAM,2BAA2B;AACjC,MAAM,6BAA6B;AAEnC,SAAS,UACL,OACA,UACA,UACA,YACM;CACN,IAAI,aAAa,QAAW,OAAO;CACnC,IAAI,CAAC,OAAO,SAAS,QAAQ,KAAK,YAAY,GAC1C,MAAM,IAAI,cAAc,kBAAkB,uBAAuB,CAC7D,YACA,aAAa,MAAM,mDACvB,CAAC;CAEL,OAAO;AACX;;AAGA,SAAgB,qBACZ,MACA,YAC2B;CAC3B,OAAO;EACH,MAAM;GACF,OAAO,MAAM,MAAM;GACnB,SAAS,UAAU,QAAQ,MAAM,MAAM,SAAS,yBAAyB,UAAU;EACvF;EACA,OAAO,EACH,SAAS,UAAU,SAAS,MAAM,OAAO,SAAS,0BAA0B,UAAU,EAC1F;EACA,SAAS;GACL,OAAO,MAAM,SAAS;GACtB,SAAS,UAAU,WAAW,MAAM,SAAS,SAAS,4BAA4B,UAAU;EAChG;CACJ;AACJ;;;;;ACzCA,MAAM,mBAAmB,OAAO,sBAAsB;;AAEtD,MAAM,aAAa,OAAO,wBAAwB;;;;;;;;AASlD,IAAsB,SAAtB,MAEA;CAiByB;;CATrB,CAAU;;CAEV,CAAU;;CAGV,AAAmB;CAGnB,YACI,AAAiB,MACjB,MACF;EAFmB;EAGjB,KAAK,SAAS,IAAI,OAAO,KAAK,YAAY,IAAI;EAC9C,KAAK,cAAc,KAAK;EACxB,KAAK,oBAAoB,qBAAqB,MAAM,KAAK,YAAY,IAAI;CAC7E;;CAGA,IAAc,OAAc;EAExB,OAAO,KAAK;CAChB;;;;;;CAkBA,AAAU,cAAc,QAAuB;EAC3C,MAAM,IAAI,cAAc,kBAAkB,uBAAuB,CAAC,KAAK,YAAY,MAAM,MAAM,CAAC;CACpG;;CAGA,AAAO,MAAM,QAAuC;EAChD,OAAO,QAAQ,QAAQ;CAC3B;;;;;CAMA,AAAU,sBAAsB,UAA0B;EACtD,cAAc,CAAC,EAAE,KAAK,oCAAoC,EAAE,SAAS,CAAC;CAC1E;AACJ;;AAGA,SAAgB,wBAAwB,QAAiD;CACrF,OAAO,OAAO;AAClB;;AAGA,SAAgB,eAAe,QAA4B;CACvD,OAAO,OAAO;AAClB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as CommandBuilder, r as DeployResult, t as Constructor } from "./basic-Dng__Ena.mjs";
|
|
2
|
-
import { H as InteractionRoutes, O as Notice, g as CoreBase, j as AckState, k as ReplyTelemetry } from "./Plugin-
|
|
2
|
+
import { H as InteractionRoutes, O as Notice, g as CoreBase, j as AckState, k as ReplyTelemetry } from "./Plugin-B6iRzm3g.mjs";
|
|
3
3
|
import "reflect-metadata";
|
|
4
4
|
import { ActionRowBuilder, ButtonBuilder, ChannelSelectMenuBuilder, CheckboxBuilder, CheckboxGroupBuilder, CheckboxGroupOptionBuilder, ContainerBuilder, ContextMenuCommandBuilder, EmbedBuilder, FileBuilder, FileUploadBuilder, LabelBuilder, MediaGalleryBuilder, MentionableSelectMenuBuilder, ModalBuilder, RadioGroupBuilder, RadioGroupOptionBuilder, RoleSelectMenuBuilder, SectionBuilder, SeparatorBuilder, SlashCommandBuilder, SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder, StringSelectMenuBuilder, StringSelectMenuOptionBuilder, TextDisplayBuilder, TextInputBuilder, UserSelectMenuBuilder } from "@discordjs/builders";
|
|
5
5
|
import { APIMessageTopLevelComponent, APIModalInteractionResponseCallbackData, ApplicationCommandType, ChannelType, Snowflake } from "discord-api-types/v10";
|
|
@@ -784,7 +784,7 @@ interface EffectGate<Ctx extends GateContextBase = GateContextBase, Name extends
|
|
|
784
784
|
* @param fn - The check, which refuses by throwing a Notice or a Silence and passes by returning.
|
|
785
785
|
*
|
|
786
786
|
* @see {@link defineEffectGate}
|
|
787
|
-
* @see the `@Gated` decorator from
|
|
787
|
+
* @see the `@Gated` decorator from your transport package
|
|
788
788
|
*
|
|
789
789
|
* @example
|
|
790
790
|
* ```ts
|
|
@@ -819,7 +819,7 @@ declare function defineGate<const Name extends string, Ctx extends GateContextBa
|
|
|
819
819
|
* @param commit - Applies the side effect, running only after the whole gate set passes.
|
|
820
820
|
*
|
|
821
821
|
* @see {@link defineGate}
|
|
822
|
-
* @see the `@Gated` decorator from
|
|
822
|
+
* @see the `@Gated` decorator from your transport package
|
|
823
823
|
* @see {@link Cooldown}
|
|
824
824
|
*
|
|
825
825
|
* @example
|
|
@@ -858,7 +858,7 @@ type IntersectRequired<Gates extends readonly Gate<GateContextBase>[]> = Gates e
|
|
|
858
858
|
type TwoOrMore<Item> = readonly [Item, Item, ...Item[]];
|
|
859
859
|
type GateName<TGate> = TGate extends Gate<GateContextBase, infer Name> ? Name : string;
|
|
860
860
|
type JoinNames<Gates extends readonly Gate<GateContextBase>[], Sep extends string> = Gates extends readonly [infer Only extends Gate<GateContextBase>] ? GateName<Only> : Gates extends readonly [infer First extends Gate<GateContextBase>, ...infer Rest extends readonly Gate<GateContextBase>[]] ? `${GateName<First>}${Sep}${JoinNames<Rest, Sep>}` : string;
|
|
861
|
-
type GateMismatch<Name extends string, Want extends string, Got extends string> = `gate '${Name}'
|
|
861
|
+
type GateMismatch<Name extends string, Want extends string, Got extends string> = `gate '${Name}' requires a ${Want} handler, and this handler is ${Got}`;
|
|
862
862
|
type GateFitsWith<Provided, ProvidedLabel extends string, TGate, ReqLabel extends string> = [Provided] extends [RequiredOf<TGate>] ? TGate : Constructor<[GateMismatch<GateName<TGate>, ReqLabel, ProvidedLabel>]>;
|
|
863
863
|
//#endregion
|
|
864
864
|
//#region src/gates/catalog/options.d.ts
|
|
@@ -933,7 +933,7 @@ interface RequireRoleOptions {
|
|
|
933
933
|
* @param scope - The permission flag bits the caller must all hold.
|
|
934
934
|
* @param options - Pick the scope with `in`, and override each refusal with `notInGuild` or `missing`.
|
|
935
935
|
*
|
|
936
|
-
* @see the `@Gated` decorator from
|
|
936
|
+
* @see the `@Gated` decorator from your transport package
|
|
937
937
|
*
|
|
938
938
|
* @example
|
|
939
939
|
* ```ts
|
|
@@ -973,7 +973,7 @@ declare function RequirePermissions(scope: PermissionScope, options?: RequirePer
|
|
|
973
973
|
* @param scope - The permission flag bits the bot must all hold.
|
|
974
974
|
* @param options - Pick the scope with `in`, and override each refusal with `notInGuild` or `missing`.
|
|
975
975
|
*
|
|
976
|
-
* @see the `@Gated` decorator from
|
|
976
|
+
* @see the `@Gated` decorator from your transport package
|
|
977
977
|
*
|
|
978
978
|
* @example
|
|
979
979
|
* ```ts
|
|
@@ -1001,7 +1001,7 @@ declare function RequireBotPermissions(scope: PermissionScope, options?: Require
|
|
|
1001
1001
|
* @param roleId - The role snowflake the caller must hold.
|
|
1002
1002
|
* @param options - Override each refusal, the outside-guild one with `notInGuild` and the missing-role one with `missingRole`.
|
|
1003
1003
|
*
|
|
1004
|
-
* @see the `@Gated` decorator from
|
|
1004
|
+
* @see the `@Gated` decorator from your transport package
|
|
1005
1005
|
*
|
|
1006
1006
|
* @example
|
|
1007
1007
|
* ```ts
|
|
@@ -1066,4 +1066,4 @@ type PageCursor<Prefix extends string> = CustomId<Prefix, {
|
|
|
1066
1066
|
declare function pageCursor<Prefix extends string>(prefix: Prefix): PageCursor<Prefix>;
|
|
1067
1067
|
//#endregion
|
|
1068
1068
|
export { Promisable as $, ModalLike as A, areRoutes as B, Gate as C, defineEffectGate as D, RequiredOf as E, ComponentKindBrand as F, storeInteractionRoute as G, interactionRoutesOf as H, ContextMenuKindBrand as I, decodeFor as J, AnyCustomId as K, SlashRouteBrand as L, serializeReply as M, AutocompleteRouteBrand as N, defineGate as O, ComponentDefsBrand as P, RegisterCommand as Q, RoutableConstructor as R, EffectGate as S, GuildPermissionsContext as T, selectMenuRouteOf as U, contextMenuRouteOf as V, storeComponentRoute as W, DecodedParams as X, prefixOf as Y, CommandMeta as Z, pickNotice as _, UserContextMenuRegistry as _t, AutocompleteOptions as a, CommandInfo as at, JoinNames as b, FocusedField as c, ContextMenuInfo as ct, RequirePermissionsOptions as d, InjectedContextMenuMap as dt, IsNever as et, RequireRole as f, OptionKind as ft, GateNoticeOptions as g, MessageContextMenuRegistry as gt, PermissionScope as h, ContextMenuKind as ht, AutocompletableNames as i, RowType as it, SerializedReply as j, BaseReplySender as k, RequireBotPermissions as l, ContextMenus as lt, PermissionNames as m, SlashOptionRegistry as mt, PageCursor as n, RowComponent as nt, ChoiceValueOf as o, CommandInjector as ot, RequireRoleOptions as p, SlashOption as pt, CustomId as q, pageCursor as r, BuilderType as rt, EntryFor as s, Commands as st, PAGE_MAX as t, BuilderComponent as tt, RequirePermissions as u, InjectedCommandMap as ut, GateFitsWith as v, GateContextBase as w, TwoOrMore as x, IntersectRequired as y, SelectMenuKind as z };
|
|
1069
|
-
//# sourceMappingURL=cursor-
|
|
1069
|
+
//# sourceMappingURL=cursor-0Dpi07Sj.d.mts.map
|
|
@@ -728,7 +728,7 @@ function contextMenuRouteOf(kind) {
|
|
|
728
728
|
* @param fn - The check, which refuses by throwing a Notice or a Silence and passes by returning.
|
|
729
729
|
*
|
|
730
730
|
* @see {@link defineEffectGate}
|
|
731
|
-
* @see the `@Gated` decorator from
|
|
731
|
+
* @see the `@Gated` decorator from your transport package
|
|
732
732
|
*
|
|
733
733
|
* @example
|
|
734
734
|
* ```ts
|
|
@@ -768,7 +768,7 @@ function defineGate(name, fn) {
|
|
|
768
768
|
* @param commit - Applies the side effect, running only after the whole gate set passes.
|
|
769
769
|
*
|
|
770
770
|
* @see {@link defineGate}
|
|
771
|
-
* @see the `@Gated` decorator from
|
|
771
|
+
* @see the `@Gated` decorator from your transport package
|
|
772
772
|
* @see {@link Cooldown}
|
|
773
773
|
*
|
|
774
774
|
* @example
|
|
@@ -988,7 +988,7 @@ function RequireBotPermissions(scope, options) {
|
|
|
988
988
|
* @param roleId - The role snowflake the caller must hold.
|
|
989
989
|
* @param options - Override each refusal, the outside-guild one with `notInGuild` and the missing-role one with `missingRole`.
|
|
990
990
|
*
|
|
991
|
-
* @see the `@Gated` decorator from
|
|
991
|
+
* @see the `@Gated` decorator from your transport package
|
|
992
992
|
*
|
|
993
993
|
* @example
|
|
994
994
|
* ```ts
|
|
@@ -1049,4 +1049,4 @@ function pageCursor(prefix) {
|
|
|
1049
1049
|
|
|
1050
1050
|
//#endregion
|
|
1051
1051
|
export { areRoutes as A, prefixOf as B, NotInDm as C, defineEffectGate as D, OnCooldown as E, storeInteractionRoute as F, ContextMenus as G, Notice as H, ComponentDefsKey as I, guardedAccessor as J, accessorStore as K, decodeComponentRoute as L, interactionRoutesOf as M, selectMenuRouteOf as N, defineGate as O, storeComponentRoute as P, CustomId as R, NotAllowed as S, NotOwner as T, CommandInjector as U, NoticeCard as V, Commands as W, GateNotice as _, RequirePermissions as a, MissingRole as b, hasAll as c, pickNotice as d, discardCommits as f, runCommits as g, runCheck as h, RequireBotPermissions as i, contextMenuRouteOf as j, SelectMenuKind as k, missingNames as l, rollbackCommits as m, pageCursor as n, RequireRole as o, markCommits as p, clearStore as q, Silence as r, PermissionNames as s, PAGE_MAX as t, presentNames as u, HasDangerousPermissions as v, NotInGuild as w, NeedsAny as x, MissingPermissions as y, decodeFor as z };
|
|
1052
|
-
//# sourceMappingURL=cursor-
|
|
1052
|
+
//# sourceMappingURL=cursor-BRyCNqRV.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor-B07ArwDz.mjs","names":[],"sources":["../src/miscellaneous/guarded.ts","../src/commands/CommandInjector.ts","../src/stops/Notice.ts","../src/stops/NoticeCard.ts","../src/customId/Errors.ts","../src/customId/codec.ts","../src/customId/CustomId.ts","../src/customId/routing.ts","../src/decorators/interactionRoutes.ts","../src/gates/Gate.ts","../src/notices/index.ts","../src/gates/effects.ts","../src/gates/catalog/options.ts","../src/permissions/bits.ts","../src/gates/catalog/permissions.ts","../src/stops/Silence.ts","../src/pagination/cursor.ts"],"sourcesContent":["import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\n// null-prototype, on a plain object a key named __proto__ sets the store's prototype and adds no entry\nexport function accessorStore<Value>(): Record<string, Value> {\n return Object.create(null) as Record<string, Value>;\n}\n\n// empties a store in place, keeping the reference the accessor's Proxy wraps\nexport function clearStore(store: Record<string, unknown>): void {\n for (const key of Object.keys(store)) Reflect.deleteProperty(store, key);\n}\n\n// handler modules import before startup fills the record, and an unguarded read there returns undefined and renders as an empty string\nexport function guardedAccessor<Value>(accessor: string, storage: Record<string, Value>): Record<string, Value> {\n return new Proxy(storage, {\n get(target, key, receiver): unknown {\n // hasOwn, since `in` walks the prototype and would read a key like `constructor` as resolved\n if (typeof key !== 'string' || Object.hasOwn(target, key)) return Reflect.get(target, key, receiver);\n throw new SeedcordError(SeedcordErrorCode.CoreAccessorUnresolved, [accessor, key]);\n }\n });\n}\n","import { SlashCommandBuilder } from '@discordjs/builders';\nimport { paint } from '@seedcord/errors';\nimport { Logger } from '@seedcord/logger';\nimport { routeLeavesOf } from '@seedcord/utils/internal';\nimport { ApplicationCommandType } from 'discord-api-types/v10';\n\nimport { contextMenuLeaves } from '#src/commands/contextMenuLeaves';\nimport { accessorStore, clearStore, guardedAccessor } from '#src/miscellaneous/guarded';\n\nimport type {\n ContextMenuKind,\n MessageContextMenuRegistry,\n UserContextMenuRegistry\n} from '#registries/ContextMenuRegistry';\nimport type { SlashOptionRegistry } from '#registries/SlashOptionRegistry';\nimport type { CommandBuilder, DeployResult } from '#src/commands/types';\nimport type { APIApplicationCommand, Snowflake } from 'discord-api-types/v10';\n\nconst commandStorage = accessorStore<CommandInfo>();\nconst userMenuStorage = accessorStore<ContextMenuInfo>();\nconst messageMenuStorage = accessorStore<ContextMenuInfo>();\n\n/** What {@link Commands} resolves to for one slash route. */\nexport interface CommandInfo {\n /** The clickable `</config set:id>` mention. A route whose id did not resolve falls back to `/config set`. */\n readonly mention: string;\n /** The deployed command id. Absent when the command deployed to two or more guilds. */\n readonly id?: string;\n /** The full route, e.g. `config/set`. */\n readonly route: string;\n /** The route's own description, taken from the subcommand for a nested route. */\n readonly description: string;\n}\n\n/** Each registered slash route mapped to its deployed command. */\nexport type InjectedCommandMap = {\n [K in keyof SlashOptionRegistry]: CommandInfo;\n};\n\n/**\n * The bot's deployed slash commands, keyed by {@link SlashOptionRegistry}. Filled by\n * {@link CommandInjector} after each deploy, and a read before that throws.\n *\n * @example\n * ```ts\n * import { Commands } from '@seedcord/gateway';\n *\n * await this.reply(`Try ${Commands['config/set'].mention}`);\n *\n * // a help listing\n * const lines = Object.values(Commands).map((c) => `${c.mention} ${c.description}`);\n * ```\n */\nexport const Commands = guardedAccessor('Commands', commandStorage) as InjectedCommandMap;\n\n/** What {@link ContextMenus} resolves to for one context-menu command. */\nexport interface ContextMenuInfo {\n /** The deployed command id. Absent when the command deployed to two or more guilds. */\n readonly id?: string;\n /** The name shown in Discord's right-click menu. */\n readonly name: string;\n readonly kind: ContextMenuKind;\n}\n\n/** Deployed context-menu commands, split by kind because Discord scopes name uniqueness per command type. */\nexport interface InjectedContextMenuMap {\n readonly user: { [K in keyof UserContextMenuRegistry]: ContextMenuInfo };\n readonly message: { [K in keyof MessageContextMenuRegistry]: ContextMenuInfo };\n}\n\n/**\n * The bot's deployed context-menu commands. Filled by {@link CommandInjector} after each deploy, and a read\n * before that throws.\n *\n * @example\n * ```ts\n * import { ContextMenus } from '@seedcord/gateway';\n *\n * const id = ContextMenus.user['View Profile'].id;\n * ```\n */\nexport const ContextMenus = {\n user: guardedAccessor('ContextMenus.user', userMenuStorage),\n message: guardedAccessor('ContextMenus.message', messageMenuStorage)\n} as InjectedContextMenuMap;\n\nconst MULTI_GUILD = Symbol('seedcord:commands:multi-guild');\n\n// Discord scopes name uniqueness per type, and a context-menu name may be all lowercase like a slash name\nfunction commandKey(type: ApplicationCommandType, name: string): string {\n return `${type}:${name}`;\n}\n\nfunction slashBuildersOf(all: readonly CommandBuilder[]): SlashCommandBuilder[] {\n const slash = all.filter((command): command is SlashCommandBuilder => command instanceof SlashCommandBuilder);\n // a guild command in N guilds is the same builder pushed once per guild\n return [...new Set(slash)];\n}\n\ninterface DeployedIds {\n readonly global: Map<string, Snowflake>;\n readonly guild: Map<string, Snowflake | typeof MULTI_GUILD>;\n readonly warned: Set<string>;\n}\n\n/** @internal */\nexport class CommandInjector {\n private readonly logger = new Logger('Commands', { channel: 'bot' });\n\n public inject(deploy: DeployResult, all: readonly CommandBuilder[]): void {\n this.clear();\n\n const ids: DeployedIds = {\n global: this.indexByKey(deploy.global),\n guild: this.indexGuilds(deploy.guilds),\n warned: new Set<string>()\n };\n let clickable = 0;\n\n for (const command of slashBuildersOf(all)) {\n const id = this.resolveId(\n ApplicationCommandType.ChatInput,\n command.name,\n ids,\n 'falling back to plain text (not clickable)'\n );\n for (const leaf of routeLeavesOf(command.toJSON())) {\n commandStorage[leaf.route] = {\n mention: id ? this.toMention(leaf.route, id) : this.toPlain(leaf.route),\n ...(id && { id }),\n route: leaf.route,\n description: leaf.description\n };\n if (id) clickable++;\n }\n }\n\n const menus = contextMenuLeaves(all);\n this.injectMenus(menus.user, ApplicationCommandType.User, userMenuStorage, ids);\n this.injectMenus(menus.message, ApplicationCommandType.Message, messageMenuStorage, ids);\n\n this.logger.utils.summary('Linked commands', {\n clickable,\n plain: Object.keys(commandStorage).length - clickable,\n 'context menus': menus.user.size + menus.message.size\n });\n }\n\n private injectMenus(\n names: ReadonlySet<string>,\n kind: ContextMenuKind,\n storage: Record<string, ContextMenuInfo>,\n ids: DeployedIds\n ): void {\n for (const name of names) {\n const id = this.resolveId(kind, name, ids, 'leaving its id unset');\n storage[name] = { ...(id && { id }), name, kind };\n }\n }\n\n private indexByKey(collection: Map<Snowflake, APIApplicationCommand>): Map<string, Snowflake> {\n const map = new Map<string, Snowflake>();\n for (const command of collection.values()) map.set(commandKey(command.type, command.name), command.id);\n return map;\n }\n\n private indexGuilds(\n guilds: Map<Snowflake, Map<Snowflake, APIApplicationCommand>>\n ): Map<string, Snowflake | typeof MULTI_GUILD> {\n const map = new Map<string, Snowflake | typeof MULTI_GUILD>();\n for (const collection of guilds.values()) {\n for (const command of collection.values()) {\n const key = commandKey(command.type, command.name);\n const existing = map.get(key);\n // Discord assigns a separate id per guild, so two ids for one name means no single mention\n if (existing === undefined) map.set(key, command.id);\n else if (existing !== command.id) map.set(key, MULTI_GUILD);\n }\n }\n return map;\n }\n\n private resolveId(\n type: ApplicationCommandType,\n name: string,\n ids: DeployedIds,\n consequence: string\n ): Snowflake | undefined {\n const key = commandKey(type, name);\n const global = ids.global.get(key);\n if (global) return global;\n\n const guild = ids.guild.get(key);\n if (guild === undefined) return undefined;\n if (guild === MULTI_GUILD) {\n if (!ids.warned.has(key)) {\n this.logger.warn(`${paint.sky.bold(name)} is deployed to multiple guilds, ${consequence}.`);\n ids.warned.add(key);\n }\n return undefined;\n }\n return guild;\n }\n\n private toMention(route: string, id: Snowflake): string {\n return `</${route.replaceAll('/', ' ')}:${id}>`;\n }\n\n private toPlain(route: string): string {\n return `/${route.replaceAll('/', ' ')}`;\n }\n\n private clear(): void {\n for (const store of [commandStorage, userMenuStorage, messageMenuStorage]) clearStore(store);\n }\n}\n","import type { RenderContext, ReplyResponse } from '@seedcord/types';\n\n/**\n * Base class for a user-facing refusal or a reported fault.\n *\n * Throw a `Notice` to stop a handler and reply to the user. The framework catches it at the controller\n * boundary and renders {@link Notice.render}, which always decides what the user sees. With `report`\n * false that render is all that happens. With `report` true the framework also logs the fault and\n * publishes it to the `handledException` bus. A raw, non-Notice throw shows the generic message.\n *\n * @example\n * ```ts\n * import { Notice, BuilderComponent, type RenderContext, type ReplyResponse } from '@seedcord/gateway';\n * import { TextDisplayBuilder } from '@discordjs/builders';\n *\n * // reading `.component` applies the configured bot color to the container accent\n * class TooPoorCard extends BuilderComponent<'container'> {\n * constructor(balance: number) {\n * super('container');\n * this.instance.addTextDisplayComponents(\n * new TextDisplayBuilder().setContent(`### Insufficient balance\\nYou need more than ${balance} coins.`)\n * );\n * }\n * }\n *\n * class TooPoor extends Notice {\n * constructor(private readonly balance: number) {\n * super(`balance ${balance} is below the cost`);\n * }\n *\n * render(_ctx: RenderContext): ReplyResponse {\n * return { components: [new TooPoorCard(this.balance).component] };\n * }\n * }\n *\n * // in a handler, throwing stops the handler and replies with render(ctx)\n * if (wallet.balance < cost) throw new TooPoor(wallet.balance);\n * ```\n */\nexport abstract class Notice extends Error {\n /**\n * Whether this denial is a reported fault. True also logs it and publishes it to the `handledException`\n * bus. The user always sees {@link Notice.render} either way.\n *\n * @defaultValue `false`\n */\n public report = false;\n\n /**\n * Whether the reply is ephemeral, seen only by the invoking user. Set it false for a refusal the\n * whole channel should see.\n *\n * @defaultValue `true`\n */\n public ephemeral = true;\n\n /**\n * A short one-line reason. When every arm of an `or` gate refuses and each refusal sets this, `or`\n * lists them as the reply.\n */\n public summary?: string;\n\n protected constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n\n // Error sets name to 'Error', so stamp the concrete subclass name for logs and the fault report\n this.name = new.target.name;\n Error.captureStackTrace(this, this.constructor);\n }\n\n /**\n * Builds what the user sees. Called fresh each time the denial is shown, so the builders are new\n * and the bot color resolves at render time.\n */\n public abstract render(ctx: RenderContext): ReplyResponse;\n}\n","import { TextDisplayBuilder } from '@discordjs/builders';\n\nimport { BuilderComponent } from '#components/Component';\n\n// built fresh inside a Notice's render to back its ComponentsV2 reply\n// discord renders the ### line as an h3 with the description below\nexport class NoticeCard extends BuilderComponent<'container'> {\n public constructor(description: string, title = 'Cannot Proceed') {\n super('container');\n this.instance.addTextDisplayComponents(new TextDisplayBuilder().setContent(`### ${title}\\n${description}`));\n }\n}\n","import { Notice } from '#stops/Notice';\nimport { NoticeCard } from '#stops/NoticeCard';\n\nimport type { ReplyResponse } from '@seedcord/types';\n\n/**\n * Thrown when a customId was minted by an older version of its shape.\n *\n * This is normal after the shape changes.\n */\nexport class StaleCustomId extends Notice {\n constructor(prefix: string) {\n super(`Stale customId for \"${prefix}\".`);\n }\n\n render(): ReplyResponse {\n const card = new NoticeCard(\n 'This button or menu is from an older version. Please run the command again.',\n 'Outdated'\n );\n return { components: [card.component] };\n }\n}\n\n/**\n * Thrown when a customId wire is corrupt or tampered with and cannot be trusted.\n *\n * It reports because this is an odd case that should not happen.\n */\nexport class InvalidCustomId extends Notice {\n constructor(detail: string) {\n super(`Invalid customId. ${detail}`);\n this.report = true;\n }\n\n render(): ReplyResponse {\n const card = new NoticeCard('Something went wrong. Please try again.');\n return { components: [card.component] };\n }\n}\n","/* eslint-disable no-magic-numbers -- lots of bigints */\n\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport { InvalidCustomId } from './Errors';\n\nimport type { CustomIdField, CustomIdShape } from './Field';\n\n// wire is routeKey, a colon, then the body. the routeKey is the stable prefix plus a short shape\n// hash, which is how decode rejects a wire minted under an older shape. bounded fields (known range)\n// fold into one base64 integer by mixed-radix packing. unbounded ones (free string, unbounded int)\n// trail it as delimited tokens.\n//\n// everything here works on runtime values (unknown). CustomId.ts adds the typed layer.\n\n// url-safe base64, one utf-16 unit per char so encode's wire.length cap counts chars exactly.\nconst ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';\nconst BASE = 64n;\nconst CHAR_TO_VALUE = new Map([...ALPHABET].map((char, index) => [char, index] as const));\n\nconst DELIMITER = '\\u{1F}';\nconst ESCAPE = '\\u{1B}';\n\n/** @internal */\nexport const HASH_LENGTH = 3;\n\nconst SAFE_MAX = BigInt(Number.MAX_SAFE_INTEGER);\nconst SAFE_MIN = BigInt(Number.MIN_SAFE_INTEGER);\n\n// toString and parseInt top out at base 36, and float64 loses integers past 2^53.\nfunction bigintToBase64(value: bigint): string {\n if (value === 0n) return ALPHABET.charAt(0);\n let text = '';\n for (let remaining = value; remaining > 0n; remaining /= BASE) {\n text = ALPHABET.charAt(Number(remaining % BASE)) + text;\n }\n return text;\n}\n\nfunction base64ToBigint(text: string): bigint {\n let value = 0n;\n for (const char of text) {\n const digit = CHAR_TO_VALUE.get(char);\n if (digit === undefined) throw new InvalidCustomId(`bad character ${JSON.stringify(char)}`);\n value = value * BASE + BigInt(digit);\n }\n return value;\n}\n\n// zigzag keeps a small negative number short on the wire.\nfunction zigzagEncode(value: number): bigint {\n const big = BigInt(value);\n return big >= 0n ? big << 1n : (-big << 1n) - 1n;\n}\nfunction zigzagDecode(encoded: bigint): bigint {\n return (encoded & 1n) === 1n ? -((encoded + 1n) >> 1n) : encoded >> 1n;\n}\n\nfunction escapeToken(text: string): string {\n return text.replaceAll(/[\\x1B\\x1F]/g, (char) => ESCAPE + char);\n}\nfunction unescapeToken(text: string): string {\n let out = '';\n for (let i = 0; i < text.length; i++) {\n if (text.charAt(i) !== ESCAPE) {\n out += text.charAt(i);\n continue;\n }\n const next = text.charAt(i + 1);\n if (next === '') throw new InvalidCustomId('dangling escape at end of token');\n out += next;\n i++;\n }\n return out;\n}\nfunction splitTokens(body: string): string[] {\n const pieces: string[] = [];\n let current = '';\n for (let i = 0; i < body.length; i++) {\n const char = body.charAt(i);\n if (char === ESCAPE) {\n current += char + body.charAt(i + 1);\n i++;\n } else if (char === DELIMITER) {\n pieces.push(current);\n current = '';\n } else {\n current += char;\n }\n }\n pieces.push(current);\n return pieces;\n}\n\n// bounded means the full range is known. those fold into the shared packed integer.\nfunction isBounded(field: CustomIdField<unknown>): boolean {\n if (field.kind === 'int') return field.min !== undefined && field.max !== undefined;\n return field.kind === 'snowflake' || field.kind === 'uuid' || field.kind === 'bool' || field.kind === 'oneOf';\n}\n\nfunction radixOf(field: CustomIdField<unknown>): bigint {\n switch (field.kind) {\n case 'snowflake': {\n return 1n << 64n;\n }\n case 'uuid': {\n return 1n << 128n;\n }\n case 'bool': {\n return 2n;\n }\n case 'oneOf': {\n // oneOf() rejects an empty list at define time, so an empty one here came from a\n // hand-built shape.\n if (!field.choices?.length) throw new InvalidCustomId('oneOf field has no choices');\n return BigInt(field.choices.length);\n }\n case 'int': {\n // isBounded only lets a min-and-max int through. a missing bound means the shape is corrupt.\n if (field.min === undefined || field.max === undefined)\n throw new InvalidCustomId('bounded int field is missing a bound');\n // bigint before the math, max - min + 1 in float64 drops the +1 at 2^53.\n return BigInt(field.max) - BigInt(field.min) + 1n;\n }\n default: {\n throw new InvalidCustomId(`field kind ${field.kind} has no radix`);\n }\n }\n}\n\nfunction boundedToBigint(field: CustomIdField<unknown>, name: string, value: unknown): bigint {\n const slot = boundedSlot(field, name, value);\n // out of range would carry into the neighbouring field on decode.\n if (slot < 0n || slot >= radixOf(field)) outOfRange(name, value);\n return slot;\n}\n\n// a slot is the value as an integer in [0, radix).\nfunction boundedSlot(field: CustomIdField<unknown>, name: string, value: unknown): bigint {\n switch (field.kind) {\n case 'snowflake': {\n // a bad value makes BigInt() throw a bare TypeError or SyntaxError. the guard gets\n // ahead of it with the branded error.\n if (typeof value !== 'string' || !/^\\d+$/.test(value)) return outOfRange(name, value);\n return BigInt(value);\n }\n case 'uuid': {\n if (typeof value !== 'string') return outOfRange(name, value);\n const hex = value.replaceAll('-', '');\n if (!/^[0-9a-fA-F]{32}$/.test(hex)) return outOfRange(name, value);\n return BigInt(`0x${hex}`);\n }\n case 'bool': {\n return value ? 1n : 0n;\n }\n case 'oneOf': {\n const index = (field.choices ?? []).indexOf(value as string);\n return index === -1 ? outOfRange(name, value) : BigInt(index);\n }\n case 'int': {\n // eslint-disable-next-line unicorn/prefer-number-is-safe-integer -- a bounded int field may declare max up to 2**53 exactly (a power of two, exact in float64)\n if (!Number.isInteger(value)) return outOfRange(name, value);\n return BigInt((value as number) - (field.min ?? 0));\n }\n default: {\n return outOfRange(name, value);\n }\n }\n}\n\nfunction outOfRange(name: string, value: unknown): never {\n throw new SeedcordRangeError(SeedcordErrorCode.CustomIdValueOutOfRange, [name, String(value)]);\n}\n\n// inverse of boundedSlot.\nfunction bigintToBoundedValue(field: CustomIdField<unknown>, slot: bigint): unknown {\n switch (field.kind) {\n case 'snowflake': {\n return slot.toString();\n }\n case 'uuid': {\n return bigintToUuid(slot);\n }\n case 'bool': {\n return slot === 1n;\n }\n case 'oneOf': {\n return (field.choices ?? [])[Number(slot)];\n }\n case 'int': {\n return Number(slot) + (field.min ?? 0);\n }\n default: {\n throw new InvalidCustomId(`field kind ${field.kind} is not bounded`);\n }\n }\n}\n\nfunction bigintToUuid(value: bigint): string {\n const hex = value.toString(16).padStart(32, '0');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\nfunction encodeUnboundedToken(field: CustomIdField<unknown>, name: string, value: unknown): string {\n if (field.kind === 'int') {\n if (!Number.isSafeInteger(value)) outOfRange(name, value);\n return bigintToBase64(zigzagEncode(value as number));\n }\n return escapeToken(value as string);\n}\nfunction decodeUnboundedToken(field: CustomIdField<unknown>, piece: string): unknown {\n if (field.kind !== 'int') return unescapeToken(piece);\n // an empty piece means a truncated wire\n if (piece === '') throw new InvalidCustomId('empty integer token');\n const decoded = zigzagDecode(base64ToBigint(piece));\n // encode only ever takes a js number. anything past 2^53 came from somewhere else.\n if (decoded > SAFE_MAX || decoded < SAFE_MIN) throw new InvalidCustomId('integer out of safe range');\n return Number(decoded);\n}\n\n/** @internal */\nexport function computeLayoutHash(shape: CustomIdShape): string {\n // stringify escapes the choice strings. two different shapes cannot produce the same signature.\n const signature = JSON.stringify(\n Object.entries(shape).map(([name, field]) => [\n name,\n field.kind,\n isBounded(field),\n field.kind === 'oneOf' ? (field.choices ?? []) : null,\n field.kind === 'int' ? [field.min ?? null, field.max ?? null] : null\n ])\n );\n const modulus = BASE ** BigInt(HASH_LENGTH);\n let hash = 0n;\n for (const char of signature) hash = (hash * 131n + BigInt(char.charCodeAt(0))) % modulus;\n\n let text = '';\n for (let i = 0; i < HASH_LENGTH; i++) {\n text = ALPHABET.charAt(Number(hash % BASE)) + text;\n hash /= BASE;\n }\n return text;\n}\n\n/** @internal */\nexport function encodeBody(shape: CustomIdShape, values: Record<string, unknown>): string {\n const fields = Object.entries(shape);\n const pieces: string[] = [];\n\n const bounded = fields.filter(([, field]) => isBounded(field));\n if (bounded.length > 0) {\n let packed = 0n;\n for (const [name, field] of bounded)\n packed = packed * radixOf(field) + boundedToBigint(field, name, values[name]);\n pieces.push(bigintToBase64(packed));\n }\n for (const [name, field] of fields) {\n if (!isBounded(field)) pieces.push(encodeUnboundedToken(field, name, values[name]));\n }\n return pieces.join(DELIMITER);\n}\n\nfunction unpackBounded(\n bounded: [string, CustomIdField<unknown>][],\n blob: string | undefined,\n result: Record<string, unknown>\n): void {\n // zero still packs to one char. an empty block means the body was cut short.\n if (blob === undefined || blob === '') throw new InvalidCustomId('empty packed block');\n let packed = base64ToBigint(blob);\n // last field packed is the first one back out.\n for (const [name, field] of [...bounded].reverse()) {\n const radix = radixOf(field);\n result[name] = bigintToBoundedValue(field, packed % radix);\n packed /= radix;\n }\n if (packed !== 0n) throw new InvalidCustomId('leftover bits after unpacking');\n}\n\n/** @internal */\nexport function decodeBody(shape: CustomIdShape, body: string): Record<string, unknown> {\n const fields = Object.entries(shape);\n const bounded = fields.filter(([, field]) => isBounded(field));\n const unbounded = fields.filter(([, field]) => !isBounded(field));\n\n // a shape with no fields encodes to an empty body.\n const expected = (bounded.length > 0 ? 1 : 0) + unbounded.length;\n if (expected === 0) {\n if (body !== '') throw new InvalidCustomId(`expected an empty body, got ${JSON.stringify(body)}`);\n return {};\n }\n\n const pieces = splitTokens(body);\n if (pieces.length !== expected) throw new InvalidCustomId(`expected ${expected} piece(s), got ${pieces.length}`);\n\n const result: Record<string, unknown> = {};\n let cursor = 0;\n\n if (bounded.length > 0) {\n unpackBounded(bounded, pieces[cursor], result);\n cursor++;\n }\n\n for (const [name, field] of unbounded) {\n const piece = pieces[cursor];\n cursor++;\n if (piece === undefined) throw new InvalidCustomId('missing trailing piece');\n result[name] = decodeUnboundedToken(field, piece);\n }\n\n return result;\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError, SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport { computeLayoutHash, decodeBody, encodeBody, HASH_LENGTH } from './codec';\nimport { InvalidCustomId, StaleCustomId } from './Errors';\n\nimport type { CustomIdField, CustomIdShape, DecodedParams } from './Field';\nimport type { Snowflake } from 'discord-api-types/v10';\nimport type { NonEmptyTuple } from 'type-fest';\n\n// discord caps a customId at 100 chars.\nconst MAX_WIRE_LENGTH = 100;\n\nfunction routeKeyOf(wire: string): string {\n const colon = wire.indexOf(':');\n return colon === -1 ? '' : wire.slice(0, colon);\n}\n\n/** Strip the layout hash off the routeKey to recover the stable prefix the controller routes by. @internal */\nexport function prefixOf(wire: string): string {\n const key = routeKeyOf(wire);\n return key.length <= HASH_LENGTH ? '' : key.slice(0, key.length - HASH_LENGTH);\n}\n\n/**\n * A typed customId. The single source of truth shared by the component that mints it and the handler\n * that reads it. This gives you typed reads on the `.customId` field in components. Values are packed\n * into a compact wire string, which fits more of them inside Discord's 100-char limit.\n *\n * @typeParam Prefix - The stable route prefix, e.g. 'approve'.\n * @typeParam Shape - The accumulated fields, filled in by the chain.\n *\n * @example\n * ```ts\n * const ApproveId = new CustomId('approve')\n * .snowflake('userId')\n * .oneOf('action', ['approve', 'deny']);\n *\n * // Set the custom id on a button when creating it.\n * new ButtonBuilder().setCustomId(ApproveId.encode({ userId: '123', action: 'approve' }));\n *\n * // in the handler, userId comes back a string\n * const { userId, action } = this.params; // userId: string, action: 'approve' | 'deny'\n * await this.event.guild?.members.fetch(userId);\n * ```\n */\nexport class CustomId<Prefix extends string, Shape extends CustomIdShape = {}> {\n /** The stable route prefix, e.g. 'approve'. */\n readonly prefix: Prefix;\n /** The field definitions accumulated by the chain, keyed by name. */\n readonly shape: Shape;\n /** The prefix plus a short hash of the shape, the part of the wire before the colon. */\n readonly routeKey: string;\n\n constructor(prefix: Prefix, shape: Shape = {} as Shape) {\n // an empty prefix leaves the routeKey all-hash, which prefixOf then strips to nothing. a colon\n // or a control char breaks the wire framing.\n if (!prefix || /[:\\x1B\\x1F]/.test(prefix)) {\n throw new SeedcordError(SeedcordErrorCode.CustomIdInvalidPrefix, [prefix]);\n }\n this.prefix = prefix;\n this.shape = shape;\n this.routeKey = prefix + computeLayoutHash(shape);\n }\n\n // returning a fresh instance is what avoids an `as unknown as this` cast here.\n private add<Name extends string, Decoded>(\n name: Name,\n field: CustomIdField<Decoded>\n ): CustomId<Prefix, Shape & Record<Name, CustomIdField<Decoded>>> {\n // integer-like keys get reordered by js, which would scramble the field order.\n if (/^(?:0|[1-9]\\d*)$/.test(name)) throw new SeedcordError(SeedcordErrorCode.CustomIdReservedFieldName, [name]);\n // a repeat name collapses the decoded type to never and overwrites the earlier field at runtime.\n if (name in this.shape) throw new SeedcordError(SeedcordErrorCode.CustomIdDuplicateFieldName, [name]);\n // justified: the spread plus a computed key cannot be proven to the exact intersection\n const shape = { ...this.shape, [name]: field } as Shape & Record<Name, CustomIdField<Decoded>>;\n return new CustomId(this.prefix, shape);\n }\n\n /**\n * Add a Discord ID field, decoded as a string (the `Snowflake` type from discord-api-types).\n *\n * @example\n * ```ts\n * new CustomId('ban').snowflake('userId');\n * ```\n */\n snowflake<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<Snowflake>>> {\n return this.add<Name, Snowflake>(name, { kind: 'snowflake' });\n }\n\n /**\n * Add a UUID field, decoded as a lowercase uuid string.\n *\n * @example\n * ```ts\n * new CustomId('ticket').uuid('ticketId');\n * ```\n */\n uuid<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<string>>> {\n return this.add<Name, string>(name, { kind: 'uuid' });\n }\n\n /**\n * Add an integer field with no bounds, for a value up to 2^53.\n *\n * @example\n * ```ts\n * new CustomId('shop').int('amount');\n * ```\n */\n int<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>>;\n /**\n * Add an integer field bounded by min and max, so it packs into fewer characters on the wire.\n *\n * @example\n * ```ts\n * new CustomId('paginate').int('page', 1, 50);\n * ```\n */\n int<Name extends string>(\n name: Name,\n min: number,\n max: number\n ): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>>;\n int<Name extends string>(\n name: Name,\n min?: number,\n max?: number\n ): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>> {\n if (min !== undefined && max !== undefined && min > max) {\n throw new SeedcordError(SeedcordErrorCode.CustomIdInvalidBounds, [name, min, max]);\n }\n const field: CustomIdField<number> =\n min === undefined || max === undefined ? { kind: 'int' } : { kind: 'int', min, max };\n return this.add<Name, number>(name, field);\n }\n\n /**\n * Add a boolean flag.\n *\n * @example\n * ```ts\n * new CustomId('settings').bool('silent');\n * ```\n */\n bool<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<boolean>>> {\n return this.add<Name, boolean>(name, { kind: 'bool' });\n }\n\n /**\n * Add a field that is one value from a fixed list, decoded as the literal union. No `as const` needed.\n *\n * @example\n * ```ts\n * new CustomId('poll').oneOf('choice', ['yes', 'no', 'abstain']);\n * ```\n */\n oneOf<Name extends string, const Choices extends NonEmptyTuple<string>>(\n name: Name,\n choices: Choices\n ): CustomId<Prefix, Shape & Record<Name, CustomIdField<Choices[number]>>> {\n if (choices.length === 0) throw new SeedcordError(SeedcordErrorCode.CustomIdEmptyChoices, [name]);\n return this.add<Name, Choices[number]>(name, { kind: 'oneOf', choices });\n }\n\n /**\n * Add a free short text field. Avoid it where possible. It cannot be packed, which makes it the most\n * expensive field on the wire.\n *\n * @example\n * ```ts\n * new CustomId('note').str('message');\n * ```\n */\n str<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<string>>> {\n return this.add<Name, string>(name, { kind: 'string' });\n }\n\n /**\n * Mint a wire string from values. Throws if a value is out of its field's range or the wire is over 100 chars.\n *\n * @param values - One value per field, typed by the chain.\n * @returns The wire string to put on the component's customId.\n */\n encode(values: DecodedParams<Shape>): string {\n const wire = `${this.routeKey}:${encodeBody(this.shape, values)}`;\n if (wire.length > MAX_WIRE_LENGTH) {\n throw new SeedcordRangeError(SeedcordErrorCode.CustomIdWireTooLong, [wire.length]);\n }\n return wire;\n }\n\n /**\n * Read a wire string back into values.\n *\n * - This will refuse with a default Notice when the shape changed since the wire was minted.\n * - Or refuse with a different default Notice on a corrupt or foreign wire.\n *\n * @param wire - The customId string from the interaction.\n * @returns The decoded values, typed by the chain.\n */\n decode(wire: string): DecodedParams<Shape> {\n const key = routeKeyOf(wire);\n if (key !== this.routeKey) {\n // same prefix but a different hash means the shape changed since this wire was minted.\n if (prefixOf(wire) === this.prefix) throw new StaleCustomId(this.prefix);\n throw new InvalidCustomId(`routeKey ${JSON.stringify(key)} is not ${JSON.stringify(this.routeKey)}`);\n }\n // justified: the codec returns runtime values and the shape guarantees their decoded types.\n return decodeBody(this.shape, wire.slice(key.length + 1)) as DecodedParams<Shape>;\n }\n\n /** True if this wire was minted from this customId's prefix, ignoring the shape hash. */\n owns(wire: string): boolean {\n return prefixOf(wire) === this.prefix;\n }\n}\n\n/** @internal */\nexport type AnyCustomId = CustomId<string, CustomIdShape>;\n\n/**\n * The outcome of decoding a wire against several customIds, the matched prefix paired with its values.\n *\n * @internal\n */\nexport type DecodedRoute<Defs extends readonly AnyCustomId[]> = {\n [Index in keyof Defs]: Defs[Index] extends AnyCustomId\n ? { readonly prefix: Defs[Index]['prefix']; readonly params: DecodedParams<Defs[Index]['shape']> }\n : never;\n}[number];\n\n/** @internal */\nexport function decodeFor<Defs extends readonly AnyCustomId[]>(defs: Defs, wire: string): DecodedRoute<Defs> {\n const match = defs.find((def) => def.owns(wire));\n if (!match) throw new InvalidCustomId(`no customId owns ${JSON.stringify(routeKeyOf(wire))}`);\n // justified: the matched customId fixes both prefix and params together but find() loses that link.\n return { prefix: match.prefix, params: match.decode(wire) } as DecodedRoute<Defs>;\n}\n","import 'reflect-metadata';\n\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { decodeFor } from './CustomId';\n\nimport type { ComponentDefsBrand } from '#src/decorators/brands';\nimport type { AnyCustomId } from './CustomId';\nimport type { DecodedParams } from './Field';\nimport type { Promisable } from 'type-fest';\n\n/**\n * route decorators store a handler's customId defs here, so the component base can decode\n * against them at runtime.\n *\n * @internal\n */\nexport const ComponentDefsKey = Symbol('seedcord:customId:componentDefs');\n\n/**\n * the phantom a component handler base carries. a route decorator constrains its argument to this, so\n * passing different defs to the decorator and the handler's generic is a compile error. never set at runtime.\n *\n * @internal\n */\nexport interface HasComponentDefs<Defs extends readonly AnyCustomId[]> {\n /** @internal */\n readonly [ComponentDefsBrand]?: Defs;\n}\n\n/** @internal */\nexport interface DecodedComponentRoute {\n prefix: string;\n params: Record<string, unknown>;\n}\n\n/**\n * throws `CustomIdHandlerRouteMissing` when the class has no stored defs. a drifted or corrupt wire\n * throws `StaleCustomId` or `InvalidCustomId`.\n *\n * @internal\n */\nexport function decodeComponentRoute(handlerClass: { name: string }, wire: string): DecodedComponentRoute {\n const defs = Reflect.getMetadata(ComponentDefsKey, handlerClass) as readonly AnyCustomId[] | undefined;\n if (!defs) throw new SeedcordError(SeedcordErrorCode.CustomIdHandlerRouteMissing, [handlerClass.name]);\n return decodeFor(defs, wire);\n}\n\n/** @internal */\nexport type SingleParams<Defs extends readonly AnyCustomId[]> = Defs extends readonly [infer One extends AnyCustomId]\n ? DecodedParams<One['shape']>\n : never;\n\n/** @internal */\nexport type MatchArms<Defs extends readonly AnyCustomId[], Ret> = {\n [Def in Defs[number] as Def['prefix']]: (params: DecodedParams<Def['shape']>) => Promisable<Ret>;\n};\n","import 'reflect-metadata';\n\nimport { ApplicationCommandType } from 'discord-api-types/v10';\n\nimport { ComponentDefsKey } from '#customId/routing';\nimport { InteractionMetadataKey, InteractionRouteKeys, InteractionRoutes } from '#src/metadataKeys';\n\nimport type { AnyCustomId } from '#customId/CustomId';\nimport type { ContextMenuKind } from '#registries/ContextMenuRegistry';\n\n/** The select menu kinds the select route decorators take. */\nexport enum SelectMenuKind {\n String = 'string',\n User = 'user',\n Role = 'role',\n Channel = 'channel',\n Mentionable = 'mentionable'\n}\n\n// loose on purpose, each transport's typed decorators pass their asserted ctors straight in\nexport type RoutableConstructor = new (...args: never[]) => unknown;\n\nexport function areRoutes(routes: unknown): routes is string[] {\n return Array.isArray(routes) && routes.every((route) => typeof route === 'string');\n}\n\n/**\n * every stored route kind and its route strings on a decorated constructor. the build's manifest\n * emitter reads the same pairs.\n */\nexport function interactionRoutesOf(constructor: RoutableConstructor): [InteractionRoutes, string[]][] {\n const pairs: [InteractionRoutes, string[]][] = [];\n for (const route of Object.values(InteractionRoutes)) {\n const meta: unknown = Reflect.getMetadata(InteractionRouteKeys[route], constructor);\n if (areRoutes(meta)) pairs.push([route, meta]);\n }\n return pairs;\n}\n\nexport function storeInteractionRoute(\n route: InteractionRoutes,\n routes: string | readonly string[],\n constructor: RoutableConstructor\n): void {\n const key = InteractionRouteKeys[route];\n const saved: unknown = Reflect.getMetadata(key, constructor);\n const existing = areRoutes(saved) ? saved : [];\n const toStore = typeof routes === 'string' ? [routes] : routes;\n Reflect.defineMetadata(key, [...existing, ...toStore], constructor);\n Reflect.defineMetadata(InteractionMetadataKey, true, constructor);\n}\n\n// each definition's stable prefix is the routing key\n// the full defs stay on the ctor for decoding\nexport function storeComponentRoute(\n route: InteractionRoutes,\n defs: readonly AnyCustomId[],\n constructor: RoutableConstructor\n): void {\n storeInteractionRoute(\n route,\n defs.map((def) => def.prefix),\n constructor\n );\n Reflect.defineMetadata(ComponentDefsKey, defs, constructor);\n}\n\nconst SELECT_ROUTES: Record<SelectMenuKind, InteractionRoutes> = {\n [SelectMenuKind.String]: InteractionRoutes.StringMenu,\n [SelectMenuKind.User]: InteractionRoutes.UserMenu,\n [SelectMenuKind.Role]: InteractionRoutes.RoleMenu,\n [SelectMenuKind.Channel]: InteractionRoutes.ChannelMenu,\n [SelectMenuKind.Mentionable]: InteractionRoutes.MentionableMenu\n};\n\nexport function selectMenuRouteOf(kind: SelectMenuKind): InteractionRoutes {\n return SELECT_ROUTES[kind];\n}\n\nexport function contextMenuRouteOf(kind: ContextMenuKind): InteractionRoutes {\n return kind === ApplicationCommandType.User\n ? InteractionRoutes.UserContextMenu\n : InteractionRoutes.MessageContextMenu;\n}\n","import type { CoreBase } from '#interfaces/CoreBase';\n\n/**\n * The transport-agnostic gate context, the scalar identity of the acting user resolvable from any\n * transport's payload. Every field except `core` is nullable, since an event or DM may carry no\n * guild or member. Each transport extends it with its own arm. For example, the gateway adds the djs\n * `user`/`guild`/`member` objects and the live interaction or event payload.\n *\n * @example\n * ```ts\n * // a gate reading only the base fields fits any handler on any transport\n * const NeedsGuild = defineGate('NeedsGuild', (ctx: GateContextBase) => {\n * if (!ctx.guildId) throw new NotInGuild();\n * });\n * ```\n */\nexport interface GateContextBase {\n /** Gates read the config and the rate limiter through it. */\n readonly core: CoreBase;\n /** The acting user's id, or null on an event that carries none. */\n readonly userId: string | null;\n /** The guild id, or null outside a guild. */\n readonly guildId: string | null;\n /** The channel id, or null when the source carries none. */\n readonly channelId: string | null;\n /**\n * The member's role ids without the everyone role, the shape a raw interaction payload\n * contains. Empty outside a guild or when the source contains none.\n */\n readonly memberRoleIds: readonly string[];\n /**\n * The member's permission bits, or null outside a guild. On an interaction these are the\n * channel-scoped permissions the payload contains, and on a gateway event they're the member's guild-level ones.\n */\n readonly memberPermissions: bigint | null;\n /**\n * The bot's permissions in the invoked channel, the wire `app_permissions` value. Null on gateway events.\n */\n readonly appPermissions: bigint | null;\n /**\n * The dispatched handler as `kind:route` (`slash:daily`, `button:confirm`), or null off a route (a\n * plain event handler, or a gate run outside a handler). `runHandlerGates` sets it from the handler's\n * metadata. `Cooldown` uses it so its window is stable across restarts and isolates.\n */\n readonly routeId: string | null;\n}\n\n/**\n * The context the guild-scoped permission gates require. It adds the base permission sets computed from\n * roles alone, which only the gateway transport can provide from its cache. The http transport's context\n * does not define these fields.\n *\n * @example\n * ```ts\n * // in:'guild' returns a Gate<GuildPermissionsContext>, which fits only a gateway handler\n * \\@Gated(RequirePermissions([PermissionFlagsBits.BanMembers], { in: 'guild' }))\n * ```\n */\nexport interface GuildPermissionsContext extends GateContextBase {\n /**\n * The member's base permission set, roles only, matching djs `GuildMember.permissions`. Null when the\n * member is unavailable.\n */\n readonly memberGuildPermissions: bigint | null;\n /**\n * The bot's base permission set from the transport's cache. Null when the cached member is unavailable.\n */\n readonly appGuildPermissions: bigint | null;\n}\n\n// phantom brand rejects a bare check function or plain object where a Gate is expected\ndeclare const GateBrand: unique symbol;\n\n/**\n * A precondition attached to a handler. It refuses by throwing a `Notice` (a reply) or a `Silence`\n * (a drop with no reply), and passes by returning. `Ctx` is the context it requires, so a gate that reads\n * a field absent on a handler's context is rejected at compile time. `Name` is captured as a literal so\n * a mismatch error can name the gate. Build one with {@link defineGate} or {@link defineEffectGate}.\n *\n * @typeParam Ctx - The context the gate requires. A field missing from it is a compile error.\n * @typeParam Name - The gate's literal name, named in a mismatch error.\n *\n * @example\n * ```ts\n * // a factory returning a typed, agnostic gate\n * function MyGate(): Gate<GateContextBase, 'MyGate'> {\n * return defineGate('MyGate', (ctx) => {\n * if (shouldRefuse(ctx)) throw new MyNotice();\n * });\n * }\n * ```\n *\n * @see {@link defineGate}\n */\nexport interface Gate<Ctx extends GateContextBase = GateContextBase, Name extends string = string> {\n /** The gate's name, surfaced in a mismatch error and joined by the combinators. */\n readonly name: Name;\n /** Reads the context and refuses by throwing a Notice or a Silence, or passes by resolving. */\n check(ctx: Ctx): Promise<void>;\n\n /** @internal */\n readonly [GateBrand]: true;\n}\n\n/**\n * A gate that carries a side effect, split so the effect fires only once the gate is the one that\n * let the request through. `check` peeks and refuses, while `commit` applies the effect after the whole\n * gate set passes. {@link Cooldown} is the catalog gate that returns one. Build one with\n * {@link defineEffectGate}.\n *\n * @typeParam Ctx - The context both `check` and `commit` require. A field missing from it fails to compile.\n * @typeParam Name - The gate's literal name, shown when a mismatch error names the gate.\n *\n * @example\n * ```ts\n * // a factory returning a typed effect gate\n * function MyEffectGate(): EffectGate<GateContextBase, 'MyEffectGate'> {\n * return defineEffectGate(\n * 'MyEffectGate',\n * (ctx) => {\n * if (shouldRefuse(ctx)) throw new MyNotice();\n * },\n * (ctx) => {\n * applyMyEffect(ctx);\n * }\n * );\n * }\n * ```\n *\n * @see {@link defineEffectGate}\n */\nexport interface EffectGate<Ctx extends GateContextBase = GateContextBase, Name extends string = string> extends Gate<\n Ctx,\n Name\n> {\n /** Applies the side effect, run only after the whole gate set passes. */\n commit(ctx: Ctx): Promise<void>;\n}\n\n/**\n * Builds a {@link Gate} from a check. The check refuses by throwing a Notice or a Silence and passes\n * by returning. The required context is inferred from `ctx`, so annotate it as narrowly as the fields\n * the check reads. No annotation defaults to {@link GateContextBase}, an agnostic gate that fits every\n * handler.\n *\n * @typeParam Name - The gate's name, captured as a literal for mismatch errors.\n * @typeParam Ctx - The context the check reads, inferred from the `ctx` annotation.\n *\n * @param name - The gate's name, used in mismatch errors.\n * @param fn - The check, which refuses by throwing a Notice or a Silence and passes by returning.\n *\n * @see {@link defineEffectGate}\n * @see the `@Gated` decorator from `seedcord`\n *\n * @example\n * ```ts\n * // a gate factory that takes its own option and closes over it\n * function MinRoles(min: number): Gate<GateContextBase, 'MinRoles'> {\n * return defineGate('MinRoles', (ctx) => {\n * if (ctx.memberRoleIds.length < min) throw new NotEnoughRoles(min);\n * });\n * }\n * ```\n *\n * @example\n * ```ts\n * // agnostic gate (no ctx annotation): fits any handler\n * const Owner = defineGate('owner', (ctx) => {\n * if (!ctx.userId) throw new NotOwner();\n * });\n * ```\n */\nexport function defineGate<const Name extends string, Ctx extends GateContextBase = GateContextBase>(\n name: Name,\n fn: (ctx: Ctx) => void | Promise<void>\n): Gate<Ctx, Name> {\n return { name, check: async (ctx) => fn(ctx) } as Gate<Ctx, Name>;\n}\n\n/**\n * Builds an {@link EffectGate} from a `check` and a `commit`. `check` peeks and refuses by throwing, and\n * `commit` applies the side effect, running only once the whole gate set passes so a later refusal never\n * commits. In an `or`, a refusing arm's queued commit is rolled back. This is how {@link Cooldown} peeks\n * in `check` and charges the slot in `commit`.\n *\n * @typeParam Name - The gate's literal name, used to name a mismatch error.\n * @typeParam Ctx - The context both `check` and `commit` read, inferred from the `ctx` annotation.\n *\n * @param name - The gate's name, used in mismatch errors.\n * @param check - Peeks and refuses by throwing, without applying the side effect.\n * @param commit - Applies the side effect, running only after the whole gate set passes.\n *\n * @see {@link defineGate}\n * @see the `@Gated` decorator from `seedcord`\n * @see {@link Cooldown}\n *\n * @example\n * ```ts\n * // an effect-gate factory that takes its own limit and closes over it\n * function UsesPerDay(max: number): EffectGate<GateContextBase, 'UsesPerDay'> {\n * return defineEffectGate(\n * 'UsesPerDay',\n * (ctx) => {\n * // peek and refuse by throwing. do not mutate yet\n * if (usedToday(ctx.userId) >= max) throw new OutOfUsesNotice(max);\n * },\n * (ctx) => {\n * // runs only after the whole gate set passes\n * recordUse(ctx.userId);\n * }\n * );\n * }\n * ```\n */\nexport function defineEffectGate<const Name extends string, Ctx extends GateContextBase = GateContextBase>(\n name: Name,\n check: (ctx: Ctx) => void | Promise<void>,\n commit: (ctx: Ctx) => void | Promise<void>\n): EffectGate<Ctx, Name> {\n return {\n name,\n check: async (ctx) => check(ctx),\n commit: async (ctx) => commit(ctx)\n } as EffectGate<Ctx, Name>;\n}\n\n/**\n * The context a {@link Gate} requires.\n *\n * @typeParam TGate - The gate type to read the required context from.\n *\n * @example\n * ```ts\n * type OwnerCtx = RequiredOf<ReturnType<typeof OwnerOnly>>; // GateContextBase\n * ```\n */\nexport type RequiredOf<TGate> = TGate extends Gate<infer Ctx> ? Ctx : never;\n","import { toEpochSeconds } from '@seedcord/utils';\n\nimport { Notice } from '#stops/Notice';\nimport { NoticeCard } from '#stops/NoticeCard';\n\nimport type { EpochMs, ReplyResponse } from '@seedcord/types';\n\nexport abstract class GateNotice extends Notice {\n public render(): ReplyResponse {\n return { components: [new NoticeCard(this.message).component] };\n }\n}\n\nexport class NotOwner extends GateNotice {\n public constructor(message = 'Only the bot owner can use this.') {\n super(message);\n }\n}\n\nexport class NotInGuild extends GateNotice {\n public constructor(message = 'This can only be used in a server.') {\n super(message);\n }\n}\n\nexport class NotInDm extends GateNotice {\n public constructor(message = 'This can only be used in a direct message.') {\n super(message);\n }\n}\n\nexport class OnCooldown extends GateNotice {\n public constructor(\n public readonly resetAt: EpochMs,\n message?: string\n ) {\n super(message ?? `You are doing that too fast. Try again <t:${toEpochSeconds(resetAt)}:R>.`);\n }\n}\n\nexport class NotAllowed extends Notice {\n public constructor() {\n super('not allowed');\n }\n\n public render(): ReplyResponse {\n return { components: [new NoticeCard('You are not allowed to use this command.').component] };\n }\n}\n\nexport class NeedsAny extends Notice {\n public constructor(private readonly summaries: readonly string[]) {\n super('not allowed');\n }\n\n public render(): ReplyResponse {\n const bullets = this.summaries.map((summary) => `• ${summary}`).join('\\n');\n return { components: [new NoticeCard(`You need any of:\\n${bullets}`).component] };\n }\n}\n\nexport class MissingRole extends GateNotice {\n public constructor(message: string | undefined, roleId: string | null) {\n super(\n message ?? (roleId ? `You need the <@&${roleId}> role to use this.` : 'You do not have the required role.')\n );\n }\n}\n\nexport class MissingPermissions extends Notice {\n private readonly customLead: string | undefined;\n\n public constructor(\n message: string | undefined,\n private readonly subject: string | null,\n private readonly missingPerms: readonly string[]\n ) {\n super(message ?? 'A required permission is missing.');\n this.customLead = message;\n }\n\n public render(): ReplyResponse {\n const bullets = this.missingPerms.map((perm) => `• ${perm}`).join('\\n');\n const lead =\n this.customLead ??\n `${this.subject === null ? 'You are' : `${this.subject} is`} missing the following permission entries:`;\n return {\n components: [new NoticeCard(`${lead}\\n\\n${bullets}`).component]\n };\n }\n}\n\nexport class HasDangerousPermissions extends Notice {\n private readonly customLead: string | undefined;\n\n public constructor(\n message: string | undefined,\n private readonly subject: string,\n private readonly dangerousPerms: readonly string[]\n ) {\n super(message ?? 'A dangerous permission is enabled.');\n this.customLead = message;\n }\n\n public render(): ReplyResponse {\n const bullets = this.dangerousPerms.map((perm) => `• ${perm}`).join('\\n');\n const lead =\n this.customLead ?? `${this.subject} has the following permission entries that must not be enabled:`;\n return { components: [new NoticeCard(`${lead}\\n\\n${bullets}`).component] };\n }\n}\n","import type { EffectGate, Gate, GateContextBase } from './Gate';\n\ntype CommitFn = () => Promise<void>;\n\n// commits wait here until the whole gate set passes, one queue per request. the key is the context\n// itself and the map is weak, so an entry goes when its request does\nconst commitQueues = new WeakMap<GateContextBase, CommitFn[]>();\n\nfunction isEffectGate(gate: Gate<GateContextBase>): gate is EffectGate<GateContextBase> {\n return typeof (gate as Partial<EffectGate<GateContextBase>>).commit === 'function';\n}\n\n// a refused effect gate never commits. combinators call this too\nexport async function runCheck(gate: Gate<GateContextBase>, ctx: GateContextBase): Promise<void> {\n await gate.check(ctx);\n if (!isEffectGate(gate)) return;\n\n let queue = commitQueues.get(ctx);\n if (!queue) {\n queue = [];\n commitQueues.set(ctx, queue);\n }\n queue.push(() => gate.commit(ctx));\n}\n\nexport async function runCommits(ctx: GateContextBase): Promise<void> {\n const queue = commitQueues.get(ctx);\n if (!queue) return;\n for (const commit of queue) await commit();\n}\n\n// the runner calls this from a finally, refused run or not\nexport function discardCommits(ctx: GateContextBase): void {\n commitQueues.delete(ctx);\n}\n\n// an `or` arm takes this mark before it runs\nexport function markCommits(ctx: GateContextBase): number {\n return commitQueues.get(ctx)?.length ?? 0;\n}\n\n// and rolls back to it when the arm refuses, leaving no commit behind\nexport function rollbackCommits(ctx: GateContextBase, mark: number): void {\n const queue = commitQueues.get(ctx);\n if (queue && queue.length > mark) queue.length = mark;\n}\n","import type { Notice } from '#stops/Notice';\n\n/**\n * The override a catalog gate accepts. A one-line `message` reword or a full `notice` replacement. Accepted by\n * the agnostic catalog gates and, nested per refusal, by {@link RequireRole}. {@link RequirePermissions} and\n * {@link RequireBotPermissions} take `RequirePermissionsOptions` instead.\n *\n * @example\n * ```ts\n * // reword the default refusal\n * OwnerOnly({ message: 'Bot owners only.' });\n * ```\n *\n * @example\n * ```ts\n * // replace the refusal entirely, for example a translated Notice\n * GuildOnly({ notice: new MyTranslatedNotice() });\n * ```\n */\nexport interface GateNoticeOptions {\n /** Reword the default refusal, keeping its embed styling. */\n message?: string;\n /** Replace the default refusal Notice entirely, for full control or a translated copy. */\n notice?: Notice;\n}\n\nexport function pickNotice(options: GateNoticeOptions | undefined, makeDefault: (message?: string) => Notice): Notice {\n return options?.notice ?? makeDefault(options?.message);\n}\n","import { prettify } from '@seedcord/utils';\nimport { PermissionFlagsBits } from 'discord-api-types/v10';\n\n/**\n * The permission flag bits a caller or the bot must hold. Pass the `PermissionFlagsBits` values from\n * `discord-api-types/v10` (or `discord.js`).\n */\nexport type PermissionScope = readonly bigint[];\n\n// permission bit to its prettified human-readable name\nexport const PermissionNames = new Map<bigint, string>(\n Object.entries(PermissionFlagsBits).map(([key, bit]) => [bit, prettify(key)])\n);\n\nconst ADMINISTRATOR = PermissionFlagsBits.Administrator;\n\nfunction nameOf(bit: bigint): string {\n return PermissionNames.get(bit) ?? String(bit);\n}\n\n// discord treats the administrator bit as granting every permission\nfunction holds(held: bigint, bit: bigint): boolean {\n return (held & ADMINISTRATOR) === ADMINISTRATOR || (held & bit) === bit;\n}\n\n/** @internal */\nexport function hasAll(held: bigint, scope: PermissionScope): boolean {\n return scope.every((bit) => holds(held, bit));\n}\n\n/** @internal only reached once hasAll failed, so the administrator bit is absent */\nexport function missingNames(held: bigint, scope: PermissionScope): string[] {\n return scope.reduce<string[]>((names, bit) => {\n if ((held & bit) !== bit) names.push(nameOf(bit));\n return names;\n }, []);\n}\n\n/** @internal */\nexport function presentNames(held: bigint, scope: PermissionScope): string[] {\n return scope.reduce<string[]>((names, bit) => {\n if (holds(held, bit)) names.push(nameOf(bit));\n return names;\n }, []);\n}\n","import { defineGate } from '#gates/Gate';\nimport { MissingPermissions, MissingRole, NotInGuild } from '#notices/index';\nimport { hasAll, missingNames } from '#src/permissions/bits';\n\nimport { pickNotice } from './options';\n\nimport type { Gate, GateContextBase, GuildPermissionsContext } from '#gates/Gate';\nimport type { PermissionScope } from '#src/permissions/bits';\nimport type { GateNoticeOptions } from './options';\n\nexport type { PermissionScope } from '#src/permissions/bits';\nexport { PermissionNames } from '#src/permissions/bits';\n\ninterface PermCheckKind {\n unresolved: string;\n subject: string | null;\n}\n\nconst MEMBER_CHECK: PermCheckKind = {\n unresolved: 'Your server member data could not be resolved. Try again.',\n subject: null\n};\nconst BOT_CHECK: PermCheckKind = {\n unresolved: \"The bot's permissions could not be resolved. Try again.\",\n subject: 'The bot'\n};\n\nfunction refusePermissions(\n held: bigint | null,\n scope: PermissionScope,\n options: RequirePermissionsOptions | undefined,\n guildId: string | null,\n kind: PermCheckKind\n): void {\n if (held === null) {\n throw pickNotice(\n options?.notInGuild,\n (message) => new NotInGuild(message ?? (guildId ? kind.unresolved : undefined))\n );\n }\n if (hasAll(held, scope)) return;\n throw pickNotice(\n options?.missing,\n (message) => new MissingPermissions(message, kind.subject, missingNames(held, scope))\n );\n}\n\n/**\n * Options for {@link RequirePermissions} and {@link RequireBotPermissions}.\n */\nexport interface RequirePermissionsOptions {\n /**\n * The set the check reads. `'channel'` reads the effective channel set the payload carries, what\n * Discord enforces in the invoked channel. `'guild'` reads the base set from roles, available on the\n * gateway transport only.\n *\n * @defaultValue `'channel'`\n */\n in?: 'channel' | 'guild';\n /** Reword or replace the refusal shown when the set is unavailable (outside a guild, or unresolved inside one). */\n notInGuild?: GateNoticeOptions;\n /** Reword or replace the refusal shown when a permission is missing. */\n missing?: GateNoticeOptions;\n}\n\n/**\n * Options for {@link RequireRole}.\n */\nexport interface RequireRoleOptions {\n /** Reword or replace the refusal shown outside a guild. */\n notInGuild?: GateNoticeOptions;\n /** Reword or replace the refusal shown when the caller lacks the role. */\n missingRole?: GateNoticeOptions;\n}\n\n/**\n * Requires the caller to hold every permission in `scope`. Refuses outside a guild first, then when a\n * permission is missing. The Administrator bit passes any scope.\n *\n * The default `'channel'` scope reads the effective channel set the payload carries, what Discord enforces\n * in the invoked channel. The `'guild'` scope reads the base set from roles and requires a\n * {@link GuildPermissionsContext}, so it fits a gateway handler only.\n *\n * @param scope - The permission flag bits the caller must all hold.\n * @param options - Pick the scope with `in`, and override each refusal with `notInGuild` or `missing`.\n *\n * @see the `@Gated` decorator from `seedcord`\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord-api-types/v10';\n *\n * \\@Gated(RequirePermissions([PermissionFlagsBits.BanMembers]))\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // the base set from roles, on a gateway handler\n * RequirePermissions([PermissionFlagsBits.BanMembers], { in: 'guild' });\n * ```\n */\nexport function RequirePermissions(\n scope: PermissionScope,\n options: RequirePermissionsOptions & { in: 'guild' }\n): Gate<GuildPermissionsContext, 'RequirePermissions'>;\nexport function RequirePermissions(\n scope: PermissionScope,\n options?: RequirePermissionsOptions & { in?: 'channel' }\n): Gate<GateContextBase, 'RequirePermissions'>;\nexport function RequirePermissions(\n scope: PermissionScope,\n options?: RequirePermissionsOptions\n): Gate<GuildPermissionsContext, 'RequirePermissions'> | Gate<GateContextBase, 'RequirePermissions'> {\n if (options?.in === 'guild') {\n return defineGate('RequirePermissions', (ctx: GuildPermissionsContext) => {\n refusePermissions(ctx.memberGuildPermissions, scope, options, ctx.guildId, MEMBER_CHECK);\n });\n }\n return defineGate('RequirePermissions', (ctx: GateContextBase) => {\n refusePermissions(ctx.memberPermissions, scope, options, ctx.guildId, MEMBER_CHECK);\n });\n}\n\n/**\n * Requires the bot to hold every permission in `scope`. Refuses outside a guild first, then when a\n * permission is missing. The Administrator bit passes any scope.\n *\n * The default `'channel'` scope reads the bot's effective channel set (wire `app_permissions`), what\n * Discord enforces in the invoked channel. The `'guild'` scope reads the bot's base set from roles and\n * requires a {@link GuildPermissionsContext}, fitting a gateway handler only. `app_permissions` is\n * absent on gateway events, the channel scope refuses there as unresolved, use `in: 'guild'` on an\n * event handler.\n *\n * @param scope - The permission flag bits the bot must all hold.\n * @param options - Pick the scope with `in`, and override each refusal with `notInGuild` or `missing`.\n *\n * @see the `@Gated` decorator from `seedcord`\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord-api-types/v10';\n *\n * \\@Gated(RequireBotPermissions([PermissionFlagsBits.ManageMessages]))\n * \\@SlashRoute('purge')\n * class PurgeHandler extends SlashHandler<'purge'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function RequireBotPermissions(\n scope: PermissionScope,\n options: RequirePermissionsOptions & { in: 'guild' }\n): Gate<GuildPermissionsContext, 'RequireBotPermissions'>;\nexport function RequireBotPermissions(\n scope: PermissionScope,\n options?: RequirePermissionsOptions & { in?: 'channel' }\n): Gate<GateContextBase, 'RequireBotPermissions'>;\nexport function RequireBotPermissions(\n scope: PermissionScope,\n options?: RequirePermissionsOptions\n): Gate<GuildPermissionsContext, 'RequireBotPermissions'> | Gate<GateContextBase, 'RequireBotPermissions'> {\n if (options?.in === 'guild') {\n return defineGate('RequireBotPermissions', (ctx: GuildPermissionsContext) => {\n refusePermissions(ctx.appGuildPermissions, scope, options, ctx.guildId, BOT_CHECK);\n });\n }\n return defineGate('RequireBotPermissions', (ctx: GateContextBase) => {\n refusePermissions(ctx.appPermissions, scope, options, ctx.guildId, BOT_CHECK);\n });\n}\n\n/**\n * Requires the caller to hold `roleId`, read from the member's role ids. Refuses outside a guild first,\n * then when the role is missing. Roles are guild-global, so there is no scope dimension.\n *\n * @param roleId - The role snowflake the caller must hold.\n * @param options - Override each refusal, the outside-guild one with `notInGuild` and the missing-role one with `missingRole`.\n *\n * @see the `@Gated` decorator from `seedcord`\n *\n * @example\n * ```ts\n * \\@Gated(RequireRole('123456789012345678'))\n * \\@SlashRoute('vip')\n * class VipHandler extends SlashHandler<'vip'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function RequireRole(roleId: string, options?: RequireRoleOptions): Gate<GateContextBase, 'RequireRole'> {\n return defineGate('RequireRole', (ctx) => {\n if (!ctx.guildId) throw pickNotice(options?.notInGuild, (message) => new NotInGuild(message));\n if (ctx.memberRoleIds.includes(roleId)) return;\n throw pickNotice(options?.missingRole, (message) => new MissingRole(message, roleId));\n });\n}\n","/**\n * Throw to stop a handler with no reply and no report.\n *\n * The framework boundary catches `Silence` before {@link Notice}, makes zero Discord calls, and stops.\n * Ideally you'd only throw this in `EventHandlers` (or `Gates` for those), because it doesn't make sense to\n * leave the user with no reply for an interaction.\n *\n * @example\n * ```ts\n * import { Silence } from '@seedcord/gateway';\n *\n * // before any reply or defer, drop the interaction with no reply and no report\n * if (await isBlacklisted(interaction.user.id)) throw new Silence('blacklisted user');\n * ```\n */\nexport class Silence extends Error {\n /**\n * @param reason - Optional note written only to a debug log, never shown to the user or reported.\n */\n public constructor(public readonly reason?: string) {\n super(reason ?? 'Silence');\n\n Error.captureStackTrace(this, this.constructor);\n }\n}\n","import { CustomId } from '#customId/CustomId';\n\nimport type { CustomIdField } from '#customId/Field';\n\n// Included in the layout hash so it is fixed per prefix. Reducing it marks every active button as StaleCustomId.\n// @internal\nexport const PAGE_MAX = 1_000_000;\n\n// Discord rejects a message with duplicate custom_ids, and two controls can target the same page (first and\n// prev both hit 0).\n// @internal\nconst SLOT_MAX = 4;\n\n/** Page cursor for a paginator. */\nexport type PageCursor<Prefix extends string> = CustomId<\n Prefix,\n { page: CustomIdField<number>; slot: CustomIdField<number> }\n>;\n\n/** Build the page cursor for a paginator. */\nexport function pageCursor<Prefix extends string>(prefix: Prefix): PageCursor<Prefix> {\n return new CustomId(prefix).int('page', 0, PAGE_MAX).int('slot', 0, SLOT_MAX);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cursor-BRyCNqRV.mjs","names":[],"sources":["../src/miscellaneous/guarded.ts","../src/commands/CommandInjector.ts","../src/stops/Notice.ts","../src/stops/NoticeCard.ts","../src/customId/Errors.ts","../src/customId/codec.ts","../src/customId/CustomId.ts","../src/customId/routing.ts","../src/decorators/interactionRoutes.ts","../src/gates/Gate.ts","../src/notices/index.ts","../src/gates/effects.ts","../src/gates/catalog/options.ts","../src/permissions/bits.ts","../src/gates/catalog/permissions.ts","../src/stops/Silence.ts","../src/pagination/cursor.ts"],"sourcesContent":["import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\n// null-prototype, on a plain object a key named __proto__ sets the store's prototype and adds no entry\nexport function accessorStore<Value>(): Record<string, Value> {\n return Object.create(null) as Record<string, Value>;\n}\n\n// empties a store in place, keeping the reference the accessor's Proxy wraps\nexport function clearStore(store: Record<string, unknown>): void {\n for (const key of Object.keys(store)) Reflect.deleteProperty(store, key);\n}\n\n// handler modules import before startup fills the record, and an unguarded read there returns undefined and renders as an empty string\nexport function guardedAccessor<Value>(accessor: string, storage: Record<string, Value>): Record<string, Value> {\n return new Proxy(storage, {\n get(target, key, receiver): unknown {\n // hasOwn, since `in` walks the prototype and would read a key like `constructor` as resolved\n if (typeof key !== 'string' || Object.hasOwn(target, key)) return Reflect.get(target, key, receiver);\n throw new SeedcordError(SeedcordErrorCode.CoreAccessorUnresolved, [accessor, key]);\n }\n });\n}\n","import { SlashCommandBuilder } from '@discordjs/builders';\nimport { paint } from '@seedcord/errors';\nimport { Logger } from '@seedcord/logger';\nimport { routeLeavesOf } from '@seedcord/utils/internal';\nimport { ApplicationCommandType } from 'discord-api-types/v10';\n\nimport { contextMenuLeaves } from '#src/commands/contextMenuLeaves';\nimport { accessorStore, clearStore, guardedAccessor } from '#src/miscellaneous/guarded';\n\nimport type {\n ContextMenuKind,\n MessageContextMenuRegistry,\n UserContextMenuRegistry\n} from '#registries/ContextMenuRegistry';\nimport type { SlashOptionRegistry } from '#registries/SlashOptionRegistry';\nimport type { CommandBuilder, DeployResult } from '#src/commands/types';\nimport type { APIApplicationCommand, Snowflake } from 'discord-api-types/v10';\n\nconst commandStorage = accessorStore<CommandInfo>();\nconst userMenuStorage = accessorStore<ContextMenuInfo>();\nconst messageMenuStorage = accessorStore<ContextMenuInfo>();\n\n/** What {@link Commands} resolves to for one slash route. */\nexport interface CommandInfo {\n /** The clickable `</config set:id>` mention. A route whose id did not resolve falls back to `/config set`. */\n readonly mention: string;\n /** The deployed command id. Absent when the command deployed to two or more guilds. */\n readonly id?: string;\n /** The full route, e.g. `config/set`. */\n readonly route: string;\n /** The route's own description, taken from the subcommand for a nested route. */\n readonly description: string;\n}\n\n/** Each registered slash route mapped to its deployed command. */\nexport type InjectedCommandMap = {\n [K in keyof SlashOptionRegistry]: CommandInfo;\n};\n\n/**\n * The bot's deployed slash commands, keyed by {@link SlashOptionRegistry}. Filled by\n * {@link CommandInjector} after each deploy, and a read before that throws.\n *\n * @example\n * ```ts\n * import { Commands } from '@seedcord/gateway';\n *\n * await this.reply(`Try ${Commands['config/set'].mention}`);\n *\n * // a help listing\n * const lines = Object.values(Commands).map((c) => `${c.mention} ${c.description}`);\n * ```\n */\nexport const Commands = guardedAccessor('Commands', commandStorage) as InjectedCommandMap;\n\n/** What {@link ContextMenus} resolves to for one context-menu command. */\nexport interface ContextMenuInfo {\n /** The deployed command id. Absent when the command deployed to two or more guilds. */\n readonly id?: string;\n /** The name shown in Discord's right-click menu. */\n readonly name: string;\n readonly kind: ContextMenuKind;\n}\n\n/** Deployed context-menu commands, split by kind because Discord scopes name uniqueness per command type. */\nexport interface InjectedContextMenuMap {\n readonly user: { [K in keyof UserContextMenuRegistry]: ContextMenuInfo };\n readonly message: { [K in keyof MessageContextMenuRegistry]: ContextMenuInfo };\n}\n\n/**\n * The bot's deployed context-menu commands. Filled by {@link CommandInjector} after each deploy, and a read\n * before that throws.\n *\n * @example\n * ```ts\n * import { ContextMenus } from '@seedcord/gateway';\n *\n * const id = ContextMenus.user['View Profile'].id;\n * ```\n */\nexport const ContextMenus = {\n user: guardedAccessor('ContextMenus.user', userMenuStorage),\n message: guardedAccessor('ContextMenus.message', messageMenuStorage)\n} as InjectedContextMenuMap;\n\nconst MULTI_GUILD = Symbol('seedcord:commands:multi-guild');\n\n// Discord scopes name uniqueness per type, and a context-menu name may be all lowercase like a slash name\nfunction commandKey(type: ApplicationCommandType, name: string): string {\n return `${type}:${name}`;\n}\n\nfunction slashBuildersOf(all: readonly CommandBuilder[]): SlashCommandBuilder[] {\n const slash = all.filter((command): command is SlashCommandBuilder => command instanceof SlashCommandBuilder);\n // a guild command in N guilds is the same builder pushed once per guild\n return [...new Set(slash)];\n}\n\ninterface DeployedIds {\n readonly global: Map<string, Snowflake>;\n readonly guild: Map<string, Snowflake | typeof MULTI_GUILD>;\n readonly warned: Set<string>;\n}\n\n/** @internal */\nexport class CommandInjector {\n private readonly logger = new Logger('Commands', { channel: 'bot' });\n\n public inject(deploy: DeployResult, all: readonly CommandBuilder[]): void {\n this.clear();\n\n const ids: DeployedIds = {\n global: this.indexByKey(deploy.global),\n guild: this.indexGuilds(deploy.guilds),\n warned: new Set<string>()\n };\n let clickable = 0;\n\n for (const command of slashBuildersOf(all)) {\n const id = this.resolveId(\n ApplicationCommandType.ChatInput,\n command.name,\n ids,\n 'falling back to plain text (not clickable)'\n );\n for (const leaf of routeLeavesOf(command.toJSON())) {\n commandStorage[leaf.route] = {\n mention: id ? this.toMention(leaf.route, id) : this.toPlain(leaf.route),\n ...(id && { id }),\n route: leaf.route,\n description: leaf.description\n };\n if (id) clickable++;\n }\n }\n\n const menus = contextMenuLeaves(all);\n this.injectMenus(menus.user, ApplicationCommandType.User, userMenuStorage, ids);\n this.injectMenus(menus.message, ApplicationCommandType.Message, messageMenuStorage, ids);\n\n this.logger.utils.summary('Linked commands', {\n clickable,\n plain: Object.keys(commandStorage).length - clickable,\n 'context menus': menus.user.size + menus.message.size\n });\n }\n\n private injectMenus(\n names: ReadonlySet<string>,\n kind: ContextMenuKind,\n storage: Record<string, ContextMenuInfo>,\n ids: DeployedIds\n ): void {\n for (const name of names) {\n const id = this.resolveId(kind, name, ids, 'leaving its id unset');\n storage[name] = { ...(id && { id }), name, kind };\n }\n }\n\n private indexByKey(collection: Map<Snowflake, APIApplicationCommand>): Map<string, Snowflake> {\n const map = new Map<string, Snowflake>();\n for (const command of collection.values()) map.set(commandKey(command.type, command.name), command.id);\n return map;\n }\n\n private indexGuilds(\n guilds: Map<Snowflake, Map<Snowflake, APIApplicationCommand>>\n ): Map<string, Snowflake | typeof MULTI_GUILD> {\n const map = new Map<string, Snowflake | typeof MULTI_GUILD>();\n for (const collection of guilds.values()) {\n for (const command of collection.values()) {\n const key = commandKey(command.type, command.name);\n const existing = map.get(key);\n // Discord assigns a separate id per guild, so two ids for one name means no single mention\n if (existing === undefined) map.set(key, command.id);\n else if (existing !== command.id) map.set(key, MULTI_GUILD);\n }\n }\n return map;\n }\n\n private resolveId(\n type: ApplicationCommandType,\n name: string,\n ids: DeployedIds,\n consequence: string\n ): Snowflake | undefined {\n const key = commandKey(type, name);\n const global = ids.global.get(key);\n if (global) return global;\n\n const guild = ids.guild.get(key);\n if (guild === undefined) return undefined;\n if (guild === MULTI_GUILD) {\n if (!ids.warned.has(key)) {\n this.logger.warn(`${paint.sky.bold(name)} is deployed to multiple guilds, ${consequence}.`);\n ids.warned.add(key);\n }\n return undefined;\n }\n return guild;\n }\n\n private toMention(route: string, id: Snowflake): string {\n return `</${route.replaceAll('/', ' ')}:${id}>`;\n }\n\n private toPlain(route: string): string {\n return `/${route.replaceAll('/', ' ')}`;\n }\n\n private clear(): void {\n for (const store of [commandStorage, userMenuStorage, messageMenuStorage]) clearStore(store);\n }\n}\n","import type { RenderContext, ReplyResponse } from '@seedcord/types';\n\n/**\n * Base class for a user-facing refusal or a reported fault.\n *\n * Throw a `Notice` to stop a handler and reply to the user. The framework catches it at the controller\n * boundary and renders {@link Notice.render}, which always decides what the user sees. With `report`\n * false that render is all that happens. With `report` true the framework also logs the fault and\n * publishes it to the `handledException` bus. A raw, non-Notice throw shows the generic message.\n *\n * @example\n * ```ts\n * import { Notice, BuilderComponent, type RenderContext, type ReplyResponse } from '@seedcord/gateway';\n * import { TextDisplayBuilder } from '@discordjs/builders';\n *\n * // reading `.component` applies the configured bot color to the container accent\n * class TooPoorCard extends BuilderComponent<'container'> {\n * constructor(balance: number) {\n * super('container');\n * this.instance.addTextDisplayComponents(\n * new TextDisplayBuilder().setContent(`### Insufficient balance\\nYou need more than ${balance} coins.`)\n * );\n * }\n * }\n *\n * class TooPoor extends Notice {\n * constructor(private readonly balance: number) {\n * super(`balance ${balance} is below the cost`);\n * }\n *\n * render(_ctx: RenderContext): ReplyResponse {\n * return { components: [new TooPoorCard(this.balance).component] };\n * }\n * }\n *\n * // in a handler, throwing stops the handler and replies with render(ctx)\n * if (wallet.balance < cost) throw new TooPoor(wallet.balance);\n * ```\n */\nexport abstract class Notice extends Error {\n /**\n * Whether this denial is a reported fault. True also logs it and publishes it to the `handledException`\n * bus. The user always sees {@link Notice.render} either way.\n *\n * @defaultValue `false`\n */\n public report = false;\n\n /**\n * Whether the reply is ephemeral, seen only by the invoking user. Set it false for a refusal the\n * whole channel should see.\n *\n * @defaultValue `true`\n */\n public ephemeral = true;\n\n /**\n * A short one-line reason. When every arm of an `or` gate refuses and each refusal sets this, `or`\n * lists them as the reply.\n */\n public summary?: string;\n\n protected constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n\n // Error sets name to 'Error', so stamp the concrete subclass name for logs and the fault report\n this.name = new.target.name;\n Error.captureStackTrace(this, this.constructor);\n }\n\n /**\n * Builds what the user sees. Called fresh each time the denial is shown, so the builders are new\n * and the bot color resolves at render time.\n */\n public abstract render(ctx: RenderContext): ReplyResponse;\n}\n","import { TextDisplayBuilder } from '@discordjs/builders';\n\nimport { BuilderComponent } from '#components/Component';\n\n// built fresh inside a Notice's render to back its ComponentsV2 reply\n// discord renders the ### line as an h3 with the description below\nexport class NoticeCard extends BuilderComponent<'container'> {\n public constructor(description: string, title = 'Cannot Proceed') {\n super('container');\n this.instance.addTextDisplayComponents(new TextDisplayBuilder().setContent(`### ${title}\\n${description}`));\n }\n}\n","import { Notice } from '#stops/Notice';\nimport { NoticeCard } from '#stops/NoticeCard';\n\nimport type { ReplyResponse } from '@seedcord/types';\n\n/**\n * Thrown when a customId was minted by an older version of its shape.\n *\n * This is normal after the shape changes.\n */\nexport class StaleCustomId extends Notice {\n constructor(prefix: string) {\n super(`Stale customId for \"${prefix}\".`);\n }\n\n render(): ReplyResponse {\n const card = new NoticeCard(\n 'This button or menu is from an older version. Please run the command again.',\n 'Outdated'\n );\n return { components: [card.component] };\n }\n}\n\n/**\n * Thrown when a customId wire is corrupt or tampered with and cannot be trusted.\n *\n * It reports because this is an odd case that should not happen.\n */\nexport class InvalidCustomId extends Notice {\n constructor(detail: string) {\n super(`Invalid customId. ${detail}`);\n this.report = true;\n }\n\n render(): ReplyResponse {\n const card = new NoticeCard('Something went wrong. Please try again.');\n return { components: [card.component] };\n }\n}\n","/* eslint-disable no-magic-numbers -- lots of bigints */\n\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport { InvalidCustomId } from './Errors';\n\nimport type { CustomIdField, CustomIdShape } from './Field';\n\n// wire is routeKey, a colon, then the body. the routeKey is the stable prefix plus a short shape\n// hash, which is how decode rejects a wire minted under an older shape. bounded fields (known range)\n// fold into one base64 integer by mixed-radix packing. unbounded ones (free string, unbounded int)\n// trail it as delimited tokens.\n//\n// everything here works on runtime values (unknown). CustomId.ts adds the typed layer.\n\n// url-safe base64, one utf-16 unit per char so encode's wire.length cap counts chars exactly.\nconst ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';\nconst BASE = 64n;\nconst CHAR_TO_VALUE = new Map([...ALPHABET].map((char, index) => [char, index] as const));\n\nconst DELIMITER = '\\u{1F}';\nconst ESCAPE = '\\u{1B}';\n\n/** @internal */\nexport const HASH_LENGTH = 3;\n\nconst SAFE_MAX = BigInt(Number.MAX_SAFE_INTEGER);\nconst SAFE_MIN = BigInt(Number.MIN_SAFE_INTEGER);\n\n// toString and parseInt top out at base 36, and float64 loses integers past 2^53.\nfunction bigintToBase64(value: bigint): string {\n if (value === 0n) return ALPHABET.charAt(0);\n let text = '';\n for (let remaining = value; remaining > 0n; remaining /= BASE) {\n text = ALPHABET.charAt(Number(remaining % BASE)) + text;\n }\n return text;\n}\n\nfunction base64ToBigint(text: string): bigint {\n let value = 0n;\n for (const char of text) {\n const digit = CHAR_TO_VALUE.get(char);\n if (digit === undefined) throw new InvalidCustomId(`bad character ${JSON.stringify(char)}`);\n value = value * BASE + BigInt(digit);\n }\n return value;\n}\n\n// zigzag keeps a small negative number short on the wire.\nfunction zigzagEncode(value: number): bigint {\n const big = BigInt(value);\n return big >= 0n ? big << 1n : (-big << 1n) - 1n;\n}\nfunction zigzagDecode(encoded: bigint): bigint {\n return (encoded & 1n) === 1n ? -((encoded + 1n) >> 1n) : encoded >> 1n;\n}\n\nfunction escapeToken(text: string): string {\n return text.replaceAll(/[\\x1B\\x1F]/g, (char) => ESCAPE + char);\n}\nfunction unescapeToken(text: string): string {\n let out = '';\n for (let i = 0; i < text.length; i++) {\n if (text.charAt(i) !== ESCAPE) {\n out += text.charAt(i);\n continue;\n }\n const next = text.charAt(i + 1);\n if (next === '') throw new InvalidCustomId('dangling escape at end of token');\n out += next;\n i++;\n }\n return out;\n}\nfunction splitTokens(body: string): string[] {\n const pieces: string[] = [];\n let current = '';\n for (let i = 0; i < body.length; i++) {\n const char = body.charAt(i);\n if (char === ESCAPE) {\n current += char + body.charAt(i + 1);\n i++;\n } else if (char === DELIMITER) {\n pieces.push(current);\n current = '';\n } else {\n current += char;\n }\n }\n pieces.push(current);\n return pieces;\n}\n\n// bounded means the full range is known. those fold into the shared packed integer.\nfunction isBounded(field: CustomIdField<unknown>): boolean {\n if (field.kind === 'int') return field.min !== undefined && field.max !== undefined;\n return field.kind === 'snowflake' || field.kind === 'uuid' || field.kind === 'bool' || field.kind === 'oneOf';\n}\n\nfunction radixOf(field: CustomIdField<unknown>): bigint {\n switch (field.kind) {\n case 'snowflake': {\n return 1n << 64n;\n }\n case 'uuid': {\n return 1n << 128n;\n }\n case 'bool': {\n return 2n;\n }\n case 'oneOf': {\n // oneOf() rejects an empty list at define time, so an empty one here came from a\n // hand-built shape.\n if (!field.choices?.length) throw new InvalidCustomId('oneOf field has no choices');\n return BigInt(field.choices.length);\n }\n case 'int': {\n // isBounded only lets a min-and-max int through. a missing bound means the shape is corrupt.\n if (field.min === undefined || field.max === undefined)\n throw new InvalidCustomId('bounded int field is missing a bound');\n // bigint before the math, max - min + 1 in float64 drops the +1 at 2^53.\n return BigInt(field.max) - BigInt(field.min) + 1n;\n }\n default: {\n throw new InvalidCustomId(`field kind ${field.kind} has no radix`);\n }\n }\n}\n\nfunction boundedToBigint(field: CustomIdField<unknown>, name: string, value: unknown): bigint {\n const slot = boundedSlot(field, name, value);\n // out of range would carry into the neighbouring field on decode.\n if (slot < 0n || slot >= radixOf(field)) outOfRange(name, value);\n return slot;\n}\n\n// a slot is the value as an integer in [0, radix).\nfunction boundedSlot(field: CustomIdField<unknown>, name: string, value: unknown): bigint {\n switch (field.kind) {\n case 'snowflake': {\n // a bad value makes BigInt() throw a bare TypeError or SyntaxError. the guard gets\n // ahead of it with the branded error.\n if (typeof value !== 'string' || !/^\\d+$/.test(value)) return outOfRange(name, value);\n return BigInt(value);\n }\n case 'uuid': {\n if (typeof value !== 'string') return outOfRange(name, value);\n const hex = value.replaceAll('-', '');\n if (!/^[0-9a-fA-F]{32}$/.test(hex)) return outOfRange(name, value);\n return BigInt(`0x${hex}`);\n }\n case 'bool': {\n return value ? 1n : 0n;\n }\n case 'oneOf': {\n const index = (field.choices ?? []).indexOf(value as string);\n return index === -1 ? outOfRange(name, value) : BigInt(index);\n }\n case 'int': {\n // eslint-disable-next-line unicorn/prefer-number-is-safe-integer -- a bounded int field may declare max up to 2**53 exactly (a power of two, exact in float64)\n if (!Number.isInteger(value)) return outOfRange(name, value);\n return BigInt((value as number) - (field.min ?? 0));\n }\n default: {\n return outOfRange(name, value);\n }\n }\n}\n\nfunction outOfRange(name: string, value: unknown): never {\n throw new SeedcordRangeError(SeedcordErrorCode.CustomIdValueOutOfRange, [name, String(value)]);\n}\n\n// inverse of boundedSlot.\nfunction bigintToBoundedValue(field: CustomIdField<unknown>, slot: bigint): unknown {\n switch (field.kind) {\n case 'snowflake': {\n return slot.toString();\n }\n case 'uuid': {\n return bigintToUuid(slot);\n }\n case 'bool': {\n return slot === 1n;\n }\n case 'oneOf': {\n return (field.choices ?? [])[Number(slot)];\n }\n case 'int': {\n return Number(slot) + (field.min ?? 0);\n }\n default: {\n throw new InvalidCustomId(`field kind ${field.kind} is not bounded`);\n }\n }\n}\n\nfunction bigintToUuid(value: bigint): string {\n const hex = value.toString(16).padStart(32, '0');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\nfunction encodeUnboundedToken(field: CustomIdField<unknown>, name: string, value: unknown): string {\n if (field.kind === 'int') {\n if (!Number.isSafeInteger(value)) outOfRange(name, value);\n return bigintToBase64(zigzagEncode(value as number));\n }\n return escapeToken(value as string);\n}\nfunction decodeUnboundedToken(field: CustomIdField<unknown>, piece: string): unknown {\n if (field.kind !== 'int') return unescapeToken(piece);\n // an empty piece means a truncated wire\n if (piece === '') throw new InvalidCustomId('empty integer token');\n const decoded = zigzagDecode(base64ToBigint(piece));\n // encode only ever takes a js number. anything past 2^53 came from somewhere else.\n if (decoded > SAFE_MAX || decoded < SAFE_MIN) throw new InvalidCustomId('integer out of safe range');\n return Number(decoded);\n}\n\n/** @internal */\nexport function computeLayoutHash(shape: CustomIdShape): string {\n // stringify escapes the choice strings. two different shapes cannot produce the same signature.\n const signature = JSON.stringify(\n Object.entries(shape).map(([name, field]) => [\n name,\n field.kind,\n isBounded(field),\n field.kind === 'oneOf' ? (field.choices ?? []) : null,\n field.kind === 'int' ? [field.min ?? null, field.max ?? null] : null\n ])\n );\n const modulus = BASE ** BigInt(HASH_LENGTH);\n let hash = 0n;\n for (const char of signature) hash = (hash * 131n + BigInt(char.charCodeAt(0))) % modulus;\n\n let text = '';\n for (let i = 0; i < HASH_LENGTH; i++) {\n text = ALPHABET.charAt(Number(hash % BASE)) + text;\n hash /= BASE;\n }\n return text;\n}\n\n/** @internal */\nexport function encodeBody(shape: CustomIdShape, values: Record<string, unknown>): string {\n const fields = Object.entries(shape);\n const pieces: string[] = [];\n\n const bounded = fields.filter(([, field]) => isBounded(field));\n if (bounded.length > 0) {\n let packed = 0n;\n for (const [name, field] of bounded)\n packed = packed * radixOf(field) + boundedToBigint(field, name, values[name]);\n pieces.push(bigintToBase64(packed));\n }\n for (const [name, field] of fields) {\n if (!isBounded(field)) pieces.push(encodeUnboundedToken(field, name, values[name]));\n }\n return pieces.join(DELIMITER);\n}\n\nfunction unpackBounded(\n bounded: [string, CustomIdField<unknown>][],\n blob: string | undefined,\n result: Record<string, unknown>\n): void {\n // zero still packs to one char. an empty block means the body was cut short.\n if (blob === undefined || blob === '') throw new InvalidCustomId('empty packed block');\n let packed = base64ToBigint(blob);\n // last field packed is the first one back out.\n for (const [name, field] of [...bounded].reverse()) {\n const radix = radixOf(field);\n result[name] = bigintToBoundedValue(field, packed % radix);\n packed /= radix;\n }\n if (packed !== 0n) throw new InvalidCustomId('leftover bits after unpacking');\n}\n\n/** @internal */\nexport function decodeBody(shape: CustomIdShape, body: string): Record<string, unknown> {\n const fields = Object.entries(shape);\n const bounded = fields.filter(([, field]) => isBounded(field));\n const unbounded = fields.filter(([, field]) => !isBounded(field));\n\n // a shape with no fields encodes to an empty body.\n const expected = (bounded.length > 0 ? 1 : 0) + unbounded.length;\n if (expected === 0) {\n if (body !== '') throw new InvalidCustomId(`expected an empty body, got ${JSON.stringify(body)}`);\n return {};\n }\n\n const pieces = splitTokens(body);\n if (pieces.length !== expected) throw new InvalidCustomId(`expected ${expected} piece(s), got ${pieces.length}`);\n\n const result: Record<string, unknown> = {};\n let cursor = 0;\n\n if (bounded.length > 0) {\n unpackBounded(bounded, pieces[cursor], result);\n cursor++;\n }\n\n for (const [name, field] of unbounded) {\n const piece = pieces[cursor];\n cursor++;\n if (piece === undefined) throw new InvalidCustomId('missing trailing piece');\n result[name] = decodeUnboundedToken(field, piece);\n }\n\n return result;\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError, SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport { computeLayoutHash, decodeBody, encodeBody, HASH_LENGTH } from './codec';\nimport { InvalidCustomId, StaleCustomId } from './Errors';\n\nimport type { CustomIdField, CustomIdShape, DecodedParams } from './Field';\nimport type { Snowflake } from 'discord-api-types/v10';\nimport type { NonEmptyTuple } from 'type-fest';\n\n// discord caps a customId at 100 chars.\nconst MAX_WIRE_LENGTH = 100;\n\nfunction routeKeyOf(wire: string): string {\n const colon = wire.indexOf(':');\n return colon === -1 ? '' : wire.slice(0, colon);\n}\n\n/** Strip the layout hash off the routeKey to recover the stable prefix the controller routes by. @internal */\nexport function prefixOf(wire: string): string {\n const key = routeKeyOf(wire);\n return key.length <= HASH_LENGTH ? '' : key.slice(0, key.length - HASH_LENGTH);\n}\n\n/**\n * A typed customId. The single source of truth shared by the component that mints it and the handler\n * that reads it. This gives you typed reads on the `.customId` field in components. Values are packed\n * into a compact wire string, which fits more of them inside Discord's 100-char limit.\n *\n * @typeParam Prefix - The stable route prefix, e.g. 'approve'.\n * @typeParam Shape - The accumulated fields, filled in by the chain.\n *\n * @example\n * ```ts\n * const ApproveId = new CustomId('approve')\n * .snowflake('userId')\n * .oneOf('action', ['approve', 'deny']);\n *\n * // Set the custom id on a button when creating it.\n * new ButtonBuilder().setCustomId(ApproveId.encode({ userId: '123', action: 'approve' }));\n *\n * // in the handler, userId comes back a string\n * const { userId, action } = this.params; // userId: string, action: 'approve' | 'deny'\n * await this.event.guild?.members.fetch(userId);\n * ```\n */\nexport class CustomId<Prefix extends string, Shape extends CustomIdShape = {}> {\n /** The stable route prefix, e.g. 'approve'. */\n readonly prefix: Prefix;\n /** The field definitions accumulated by the chain, keyed by name. */\n readonly shape: Shape;\n /** The prefix plus a short hash of the shape, the part of the wire before the colon. */\n readonly routeKey: string;\n\n constructor(prefix: Prefix, shape: Shape = {} as Shape) {\n // an empty prefix leaves the routeKey all-hash, which prefixOf then strips to nothing. a colon\n // or a control char breaks the wire framing.\n if (!prefix || /[:\\x1B\\x1F]/.test(prefix)) {\n throw new SeedcordError(SeedcordErrorCode.CustomIdInvalidPrefix, [prefix]);\n }\n this.prefix = prefix;\n this.shape = shape;\n this.routeKey = prefix + computeLayoutHash(shape);\n }\n\n // returning a fresh instance is what avoids an `as unknown as this` cast here.\n private add<Name extends string, Decoded>(\n name: Name,\n field: CustomIdField<Decoded>\n ): CustomId<Prefix, Shape & Record<Name, CustomIdField<Decoded>>> {\n // integer-like keys get reordered by js, which would scramble the field order.\n if (/^(?:0|[1-9]\\d*)$/.test(name)) throw new SeedcordError(SeedcordErrorCode.CustomIdReservedFieldName, [name]);\n // a repeat name collapses the decoded type to never and overwrites the earlier field at runtime.\n if (name in this.shape) throw new SeedcordError(SeedcordErrorCode.CustomIdDuplicateFieldName, [name]);\n // justified: the spread plus a computed key cannot be proven to the exact intersection\n const shape = { ...this.shape, [name]: field } as Shape & Record<Name, CustomIdField<Decoded>>;\n return new CustomId(this.prefix, shape);\n }\n\n /**\n * Add a Discord ID field, decoded as a string (the `Snowflake` type from discord-api-types).\n *\n * @example\n * ```ts\n * new CustomId('ban').snowflake('userId');\n * ```\n */\n snowflake<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<Snowflake>>> {\n return this.add<Name, Snowflake>(name, { kind: 'snowflake' });\n }\n\n /**\n * Add a UUID field, decoded as a lowercase uuid string.\n *\n * @example\n * ```ts\n * new CustomId('ticket').uuid('ticketId');\n * ```\n */\n uuid<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<string>>> {\n return this.add<Name, string>(name, { kind: 'uuid' });\n }\n\n /**\n * Add an integer field with no bounds, for a value up to 2^53.\n *\n * @example\n * ```ts\n * new CustomId('shop').int('amount');\n * ```\n */\n int<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>>;\n /**\n * Add an integer field bounded by min and max, so it packs into fewer characters on the wire.\n *\n * @example\n * ```ts\n * new CustomId('paginate').int('page', 1, 50);\n * ```\n */\n int<Name extends string>(\n name: Name,\n min: number,\n max: number\n ): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>>;\n int<Name extends string>(\n name: Name,\n min?: number,\n max?: number\n ): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>> {\n if (min !== undefined && max !== undefined && min > max) {\n throw new SeedcordError(SeedcordErrorCode.CustomIdInvalidBounds, [name, min, max]);\n }\n const field: CustomIdField<number> =\n min === undefined || max === undefined ? { kind: 'int' } : { kind: 'int', min, max };\n return this.add<Name, number>(name, field);\n }\n\n /**\n * Add a boolean flag.\n *\n * @example\n * ```ts\n * new CustomId('settings').bool('silent');\n * ```\n */\n bool<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<boolean>>> {\n return this.add<Name, boolean>(name, { kind: 'bool' });\n }\n\n /**\n * Add a field that is one value from a fixed list, decoded as the literal union. No `as const` needed.\n *\n * @example\n * ```ts\n * new CustomId('poll').oneOf('choice', ['yes', 'no', 'abstain']);\n * ```\n */\n oneOf<Name extends string, const Choices extends NonEmptyTuple<string>>(\n name: Name,\n choices: Choices\n ): CustomId<Prefix, Shape & Record<Name, CustomIdField<Choices[number]>>> {\n if (choices.length === 0) throw new SeedcordError(SeedcordErrorCode.CustomIdEmptyChoices, [name]);\n return this.add<Name, Choices[number]>(name, { kind: 'oneOf', choices });\n }\n\n /**\n * Add a free short text field. Avoid it where possible. It cannot be packed, which makes it the most\n * expensive field on the wire.\n *\n * @example\n * ```ts\n * new CustomId('note').str('message');\n * ```\n */\n str<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<string>>> {\n return this.add<Name, string>(name, { kind: 'string' });\n }\n\n /**\n * Mint a wire string from values. Throws if a value is out of its field's range or the wire is over 100 chars.\n *\n * @param values - One value per field, typed by the chain.\n * @returns The wire string to put on the component's customId.\n */\n encode(values: DecodedParams<Shape>): string {\n const wire = `${this.routeKey}:${encodeBody(this.shape, values)}`;\n if (wire.length > MAX_WIRE_LENGTH) {\n throw new SeedcordRangeError(SeedcordErrorCode.CustomIdWireTooLong, [wire.length]);\n }\n return wire;\n }\n\n /**\n * Read a wire string back into values.\n *\n * - This will refuse with a default Notice when the shape changed since the wire was minted.\n * - Or refuse with a different default Notice on a corrupt or foreign wire.\n *\n * @param wire - The customId string from the interaction.\n * @returns The decoded values, typed by the chain.\n */\n decode(wire: string): DecodedParams<Shape> {\n const key = routeKeyOf(wire);\n if (key !== this.routeKey) {\n // same prefix but a different hash means the shape changed since this wire was minted.\n if (prefixOf(wire) === this.prefix) throw new StaleCustomId(this.prefix);\n throw new InvalidCustomId(`routeKey ${JSON.stringify(key)} is not ${JSON.stringify(this.routeKey)}`);\n }\n // justified: the codec returns runtime values and the shape guarantees their decoded types.\n return decodeBody(this.shape, wire.slice(key.length + 1)) as DecodedParams<Shape>;\n }\n\n /** True if this wire was minted from this customId's prefix, ignoring the shape hash. */\n owns(wire: string): boolean {\n return prefixOf(wire) === this.prefix;\n }\n}\n\n/** @internal */\nexport type AnyCustomId = CustomId<string, CustomIdShape>;\n\n/**\n * The outcome of decoding a wire against several customIds, the matched prefix paired with its values.\n *\n * @internal\n */\nexport type DecodedRoute<Defs extends readonly AnyCustomId[]> = {\n [Index in keyof Defs]: Defs[Index] extends AnyCustomId\n ? { readonly prefix: Defs[Index]['prefix']; readonly params: DecodedParams<Defs[Index]['shape']> }\n : never;\n}[number];\n\n/** @internal */\nexport function decodeFor<Defs extends readonly AnyCustomId[]>(defs: Defs, wire: string): DecodedRoute<Defs> {\n const match = defs.find((def) => def.owns(wire));\n if (!match) throw new InvalidCustomId(`no customId owns ${JSON.stringify(routeKeyOf(wire))}`);\n // justified: the matched customId fixes both prefix and params together but find() loses that link.\n return { prefix: match.prefix, params: match.decode(wire) } as DecodedRoute<Defs>;\n}\n","import 'reflect-metadata';\n\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { decodeFor } from './CustomId';\n\nimport type { ComponentDefsBrand } from '#src/decorators/brands';\nimport type { AnyCustomId } from './CustomId';\nimport type { DecodedParams } from './Field';\nimport type { Promisable } from 'type-fest';\n\n/**\n * route decorators store a handler's customId defs here, so the component base can decode\n * against them at runtime.\n *\n * @internal\n */\nexport const ComponentDefsKey = Symbol('seedcord:customId:componentDefs');\n\n/**\n * the phantom a component handler base carries. a route decorator constrains its argument to this, so\n * passing different defs to the decorator and the handler's generic is a compile error. never set at runtime.\n *\n * @internal\n */\nexport interface HasComponentDefs<Defs extends readonly AnyCustomId[]> {\n /** @internal */\n readonly [ComponentDefsBrand]?: Defs;\n}\n\n/** @internal */\nexport interface DecodedComponentRoute {\n prefix: string;\n params: Record<string, unknown>;\n}\n\n/**\n * throws `CustomIdHandlerRouteMissing` when the class has no stored defs. a drifted or corrupt wire\n * throws `StaleCustomId` or `InvalidCustomId`.\n *\n * @internal\n */\nexport function decodeComponentRoute(handlerClass: { name: string }, wire: string): DecodedComponentRoute {\n const defs = Reflect.getMetadata(ComponentDefsKey, handlerClass) as readonly AnyCustomId[] | undefined;\n if (!defs) throw new SeedcordError(SeedcordErrorCode.CustomIdHandlerRouteMissing, [handlerClass.name]);\n return decodeFor(defs, wire);\n}\n\n/** @internal */\nexport type SingleParams<Defs extends readonly AnyCustomId[]> = Defs extends readonly [infer One extends AnyCustomId]\n ? DecodedParams<One['shape']>\n : never;\n\n/** @internal */\nexport type MatchArms<Defs extends readonly AnyCustomId[], Ret> = {\n [Def in Defs[number] as Def['prefix']]: (params: DecodedParams<Def['shape']>) => Promisable<Ret>;\n};\n","import 'reflect-metadata';\n\nimport { ApplicationCommandType } from 'discord-api-types/v10';\n\nimport { ComponentDefsKey } from '#customId/routing';\nimport { InteractionMetadataKey, InteractionRouteKeys, InteractionRoutes } from '#src/metadataKeys';\n\nimport type { AnyCustomId } from '#customId/CustomId';\nimport type { ContextMenuKind } from '#registries/ContextMenuRegistry';\n\n/** The select menu kinds the select route decorators take. */\nexport enum SelectMenuKind {\n String = 'string',\n User = 'user',\n Role = 'role',\n Channel = 'channel',\n Mentionable = 'mentionable'\n}\n\n// loose on purpose, each transport's typed decorators pass their asserted ctors straight in\nexport type RoutableConstructor = new (...args: never[]) => unknown;\n\nexport function areRoutes(routes: unknown): routes is string[] {\n return Array.isArray(routes) && routes.every((route) => typeof route === 'string');\n}\n\n/**\n * every stored route kind and its route strings on a decorated constructor. the build's manifest\n * emitter reads the same pairs.\n */\nexport function interactionRoutesOf(constructor: RoutableConstructor): [InteractionRoutes, string[]][] {\n const pairs: [InteractionRoutes, string[]][] = [];\n for (const route of Object.values(InteractionRoutes)) {\n const meta: unknown = Reflect.getMetadata(InteractionRouteKeys[route], constructor);\n if (areRoutes(meta)) pairs.push([route, meta]);\n }\n return pairs;\n}\n\nexport function storeInteractionRoute(\n route: InteractionRoutes,\n routes: string | readonly string[],\n constructor: RoutableConstructor\n): void {\n const key = InteractionRouteKeys[route];\n const saved: unknown = Reflect.getMetadata(key, constructor);\n const existing = areRoutes(saved) ? saved : [];\n const toStore = typeof routes === 'string' ? [routes] : routes;\n Reflect.defineMetadata(key, [...existing, ...toStore], constructor);\n Reflect.defineMetadata(InteractionMetadataKey, true, constructor);\n}\n\n// each definition's stable prefix is the routing key\n// the full defs stay on the ctor for decoding\nexport function storeComponentRoute(\n route: InteractionRoutes,\n defs: readonly AnyCustomId[],\n constructor: RoutableConstructor\n): void {\n storeInteractionRoute(\n route,\n defs.map((def) => def.prefix),\n constructor\n );\n Reflect.defineMetadata(ComponentDefsKey, defs, constructor);\n}\n\nconst SELECT_ROUTES: Record<SelectMenuKind, InteractionRoutes> = {\n [SelectMenuKind.String]: InteractionRoutes.StringMenu,\n [SelectMenuKind.User]: InteractionRoutes.UserMenu,\n [SelectMenuKind.Role]: InteractionRoutes.RoleMenu,\n [SelectMenuKind.Channel]: InteractionRoutes.ChannelMenu,\n [SelectMenuKind.Mentionable]: InteractionRoutes.MentionableMenu\n};\n\nexport function selectMenuRouteOf(kind: SelectMenuKind): InteractionRoutes {\n return SELECT_ROUTES[kind];\n}\n\nexport function contextMenuRouteOf(kind: ContextMenuKind): InteractionRoutes {\n return kind === ApplicationCommandType.User\n ? InteractionRoutes.UserContextMenu\n : InteractionRoutes.MessageContextMenu;\n}\n","import type { CoreBase } from '#interfaces/CoreBase';\n\n/**\n * The transport-agnostic gate context, the scalar identity of the acting user resolvable from any\n * transport's payload. Every field except `core` is nullable, since an event or DM may carry no\n * guild or member. Each transport extends it with its own arm. For example, the gateway adds the djs\n * `user`/`guild`/`member` objects and the live interaction or event payload.\n *\n * @example\n * ```ts\n * // a gate reading only the base fields fits any handler on any transport\n * const NeedsGuild = defineGate('NeedsGuild', (ctx: GateContextBase) => {\n * if (!ctx.guildId) throw new NotInGuild();\n * });\n * ```\n */\nexport interface GateContextBase {\n /** Gates read the config and the rate limiter through it. */\n readonly core: CoreBase;\n /** The acting user's id, or null on an event that carries none. */\n readonly userId: string | null;\n /** The guild id, or null outside a guild. */\n readonly guildId: string | null;\n /** The channel id, or null when the source carries none. */\n readonly channelId: string | null;\n /**\n * The member's role ids without the everyone role, the shape a raw interaction payload\n * contains. Empty outside a guild or when the source contains none.\n */\n readonly memberRoleIds: readonly string[];\n /**\n * The member's permission bits, or null outside a guild. On an interaction these are the\n * channel-scoped permissions the payload contains, and on a gateway event they're the member's guild-level ones.\n */\n readonly memberPermissions: bigint | null;\n /**\n * The bot's permissions in the invoked channel, the wire `app_permissions` value. Null on gateway events.\n */\n readonly appPermissions: bigint | null;\n /**\n * The dispatched handler as `kind:route` (`slash:daily`, `button:confirm`), or null off a route (a\n * plain event handler, or a gate run outside a handler). `runHandlerGates` sets it from the handler's\n * metadata. `Cooldown` uses it so its window is stable across restarts and isolates.\n */\n readonly routeId: string | null;\n}\n\n/**\n * The context the guild-scoped permission gates require. It adds the base permission sets computed from\n * roles alone, which only the gateway transport can provide from its cache. The http transport's context\n * does not define these fields.\n *\n * @example\n * ```ts\n * // in:'guild' returns a Gate<GuildPermissionsContext>, which fits only a gateway handler\n * \\@Gated(RequirePermissions([PermissionFlagsBits.BanMembers], { in: 'guild' }))\n * ```\n */\nexport interface GuildPermissionsContext extends GateContextBase {\n /**\n * The member's base permission set, roles only, matching djs `GuildMember.permissions`. Null when the\n * member is unavailable.\n */\n readonly memberGuildPermissions: bigint | null;\n /**\n * The bot's base permission set from the transport's cache. Null when the cached member is unavailable.\n */\n readonly appGuildPermissions: bigint | null;\n}\n\n// phantom brand rejects a bare check function or plain object where a Gate is expected\ndeclare const GateBrand: unique symbol;\n\n/**\n * A precondition attached to a handler. It refuses by throwing a `Notice` (a reply) or a `Silence`\n * (a drop with no reply), and passes by returning. `Ctx` is the context it requires, so a gate that reads\n * a field absent on a handler's context is rejected at compile time. `Name` is captured as a literal so\n * a mismatch error can name the gate. Build one with {@link defineGate} or {@link defineEffectGate}.\n *\n * @typeParam Ctx - The context the gate requires. A field missing from it is a compile error.\n * @typeParam Name - The gate's literal name, named in a mismatch error.\n *\n * @example\n * ```ts\n * // a factory returning a typed, agnostic gate\n * function MyGate(): Gate<GateContextBase, 'MyGate'> {\n * return defineGate('MyGate', (ctx) => {\n * if (shouldRefuse(ctx)) throw new MyNotice();\n * });\n * }\n * ```\n *\n * @see {@link defineGate}\n */\nexport interface Gate<Ctx extends GateContextBase = GateContextBase, Name extends string = string> {\n /** The gate's name, surfaced in a mismatch error and joined by the combinators. */\n readonly name: Name;\n /** Reads the context and refuses by throwing a Notice or a Silence, or passes by resolving. */\n check(ctx: Ctx): Promise<void>;\n\n /** @internal */\n readonly [GateBrand]: true;\n}\n\n/**\n * A gate that carries a side effect, split so the effect fires only once the gate is the one that\n * let the request through. `check` peeks and refuses, while `commit` applies the effect after the whole\n * gate set passes. {@link Cooldown} is the catalog gate that returns one. Build one with\n * {@link defineEffectGate}.\n *\n * @typeParam Ctx - The context both `check` and `commit` require. A field missing from it fails to compile.\n * @typeParam Name - The gate's literal name, shown when a mismatch error names the gate.\n *\n * @example\n * ```ts\n * // a factory returning a typed effect gate\n * function MyEffectGate(): EffectGate<GateContextBase, 'MyEffectGate'> {\n * return defineEffectGate(\n * 'MyEffectGate',\n * (ctx) => {\n * if (shouldRefuse(ctx)) throw new MyNotice();\n * },\n * (ctx) => {\n * applyMyEffect(ctx);\n * }\n * );\n * }\n * ```\n *\n * @see {@link defineEffectGate}\n */\nexport interface EffectGate<Ctx extends GateContextBase = GateContextBase, Name extends string = string> extends Gate<\n Ctx,\n Name\n> {\n /** Applies the side effect, run only after the whole gate set passes. */\n commit(ctx: Ctx): Promise<void>;\n}\n\n/**\n * Builds a {@link Gate} from a check. The check refuses by throwing a Notice or a Silence and passes\n * by returning. The required context is inferred from `ctx`, so annotate it as narrowly as the fields\n * the check reads. No annotation defaults to {@link GateContextBase}, an agnostic gate that fits every\n * handler.\n *\n * @typeParam Name - The gate's name, captured as a literal for mismatch errors.\n * @typeParam Ctx - The context the check reads, inferred from the `ctx` annotation.\n *\n * @param name - The gate's name, used in mismatch errors.\n * @param fn - The check, which refuses by throwing a Notice or a Silence and passes by returning.\n *\n * @see {@link defineEffectGate}\n * @see the `@Gated` decorator from your transport package\n *\n * @example\n * ```ts\n * // a gate factory that takes its own option and closes over it\n * function MinRoles(min: number): Gate<GateContextBase, 'MinRoles'> {\n * return defineGate('MinRoles', (ctx) => {\n * if (ctx.memberRoleIds.length < min) throw new NotEnoughRoles(min);\n * });\n * }\n * ```\n *\n * @example\n * ```ts\n * // agnostic gate (no ctx annotation): fits any handler\n * const Owner = defineGate('owner', (ctx) => {\n * if (!ctx.userId) throw new NotOwner();\n * });\n * ```\n */\nexport function defineGate<const Name extends string, Ctx extends GateContextBase = GateContextBase>(\n name: Name,\n fn: (ctx: Ctx) => void | Promise<void>\n): Gate<Ctx, Name> {\n return { name, check: async (ctx) => fn(ctx) } as Gate<Ctx, Name>;\n}\n\n/**\n * Builds an {@link EffectGate} from a `check` and a `commit`. `check` peeks and refuses by throwing, and\n * `commit` applies the side effect, running only once the whole gate set passes so a later refusal never\n * commits. In an `or`, a refusing arm's queued commit is rolled back. This is how {@link Cooldown} peeks\n * in `check` and charges the slot in `commit`.\n *\n * @typeParam Name - The gate's literal name, used to name a mismatch error.\n * @typeParam Ctx - The context both `check` and `commit` read, inferred from the `ctx` annotation.\n *\n * @param name - The gate's name, used in mismatch errors.\n * @param check - Peeks and refuses by throwing, without applying the side effect.\n * @param commit - Applies the side effect, running only after the whole gate set passes.\n *\n * @see {@link defineGate}\n * @see the `@Gated` decorator from your transport package\n * @see {@link Cooldown}\n *\n * @example\n * ```ts\n * // an effect-gate factory that takes its own limit and closes over it\n * function UsesPerDay(max: number): EffectGate<GateContextBase, 'UsesPerDay'> {\n * return defineEffectGate(\n * 'UsesPerDay',\n * (ctx) => {\n * // peek and refuse by throwing. do not mutate yet\n * if (usedToday(ctx.userId) >= max) throw new OutOfUsesNotice(max);\n * },\n * (ctx) => {\n * // runs only after the whole gate set passes\n * recordUse(ctx.userId);\n * }\n * );\n * }\n * ```\n */\nexport function defineEffectGate<const Name extends string, Ctx extends GateContextBase = GateContextBase>(\n name: Name,\n check: (ctx: Ctx) => void | Promise<void>,\n commit: (ctx: Ctx) => void | Promise<void>\n): EffectGate<Ctx, Name> {\n return {\n name,\n check: async (ctx) => check(ctx),\n commit: async (ctx) => commit(ctx)\n } as EffectGate<Ctx, Name>;\n}\n\n/**\n * The context a {@link Gate} requires.\n *\n * @typeParam TGate - The gate type to read the required context from.\n *\n * @example\n * ```ts\n * type OwnerCtx = RequiredOf<ReturnType<typeof OwnerOnly>>; // GateContextBase\n * ```\n */\nexport type RequiredOf<TGate> = TGate extends Gate<infer Ctx> ? Ctx : never;\n","import { toEpochSeconds } from '@seedcord/utils';\n\nimport { Notice } from '#stops/Notice';\nimport { NoticeCard } from '#stops/NoticeCard';\n\nimport type { EpochMs, ReplyResponse } from '@seedcord/types';\n\nexport abstract class GateNotice extends Notice {\n public render(): ReplyResponse {\n return { components: [new NoticeCard(this.message).component] };\n }\n}\n\nexport class NotOwner extends GateNotice {\n public constructor(message = 'Only the bot owner can use this.') {\n super(message);\n }\n}\n\nexport class NotInGuild extends GateNotice {\n public constructor(message = 'This can only be used in a server.') {\n super(message);\n }\n}\n\nexport class NotInDm extends GateNotice {\n public constructor(message = 'This can only be used in a direct message.') {\n super(message);\n }\n}\n\nexport class OnCooldown extends GateNotice {\n public constructor(\n public readonly resetAt: EpochMs,\n message?: string\n ) {\n super(message ?? `You are doing that too fast. Try again <t:${toEpochSeconds(resetAt)}:R>.`);\n }\n}\n\nexport class NotAllowed extends Notice {\n public constructor() {\n super('not allowed');\n }\n\n public render(): ReplyResponse {\n return { components: [new NoticeCard('You are not allowed to use this command.').component] };\n }\n}\n\nexport class NeedsAny extends Notice {\n public constructor(private readonly summaries: readonly string[]) {\n super('not allowed');\n }\n\n public render(): ReplyResponse {\n const bullets = this.summaries.map((summary) => `• ${summary}`).join('\\n');\n return { components: [new NoticeCard(`You need any of:\\n${bullets}`).component] };\n }\n}\n\nexport class MissingRole extends GateNotice {\n public constructor(message: string | undefined, roleId: string | null) {\n super(\n message ?? (roleId ? `You need the <@&${roleId}> role to use this.` : 'You do not have the required role.')\n );\n }\n}\n\nexport class MissingPermissions extends Notice {\n private readonly customLead: string | undefined;\n\n public constructor(\n message: string | undefined,\n private readonly subject: string | null,\n private readonly missingPerms: readonly string[]\n ) {\n super(message ?? 'A required permission is missing.');\n this.customLead = message;\n }\n\n public render(): ReplyResponse {\n const bullets = this.missingPerms.map((perm) => `• ${perm}`).join('\\n');\n const lead =\n this.customLead ??\n `${this.subject === null ? 'You are' : `${this.subject} is`} missing the following permission entries:`;\n return {\n components: [new NoticeCard(`${lead}\\n\\n${bullets}`).component]\n };\n }\n}\n\nexport class HasDangerousPermissions extends Notice {\n private readonly customLead: string | undefined;\n\n public constructor(\n message: string | undefined,\n private readonly subject: string,\n private readonly dangerousPerms: readonly string[]\n ) {\n super(message ?? 'A dangerous permission is enabled.');\n this.customLead = message;\n }\n\n public render(): ReplyResponse {\n const bullets = this.dangerousPerms.map((perm) => `• ${perm}`).join('\\n');\n const lead =\n this.customLead ?? `${this.subject} has the following permission entries that must not be enabled:`;\n return { components: [new NoticeCard(`${lead}\\n\\n${bullets}`).component] };\n }\n}\n","import type { EffectGate, Gate, GateContextBase } from './Gate';\n\ntype CommitFn = () => Promise<void>;\n\n// commits wait here until the whole gate set passes, one queue per request. the key is the context\n// itself and the map is weak, so an entry goes when its request does\nconst commitQueues = new WeakMap<GateContextBase, CommitFn[]>();\n\nfunction isEffectGate(gate: Gate<GateContextBase>): gate is EffectGate<GateContextBase> {\n return typeof (gate as Partial<EffectGate<GateContextBase>>).commit === 'function';\n}\n\n// a refused effect gate never commits. combinators call this too\nexport async function runCheck(gate: Gate<GateContextBase>, ctx: GateContextBase): Promise<void> {\n await gate.check(ctx);\n if (!isEffectGate(gate)) return;\n\n let queue = commitQueues.get(ctx);\n if (!queue) {\n queue = [];\n commitQueues.set(ctx, queue);\n }\n queue.push(() => gate.commit(ctx));\n}\n\nexport async function runCommits(ctx: GateContextBase): Promise<void> {\n const queue = commitQueues.get(ctx);\n if (!queue) return;\n for (const commit of queue) await commit();\n}\n\n// the runner calls this from a finally, refused run or not\nexport function discardCommits(ctx: GateContextBase): void {\n commitQueues.delete(ctx);\n}\n\n// an `or` arm takes this mark before it runs\nexport function markCommits(ctx: GateContextBase): number {\n return commitQueues.get(ctx)?.length ?? 0;\n}\n\n// and rolls back to it when the arm refuses, leaving no commit behind\nexport function rollbackCommits(ctx: GateContextBase, mark: number): void {\n const queue = commitQueues.get(ctx);\n if (queue && queue.length > mark) queue.length = mark;\n}\n","import type { Notice } from '#stops/Notice';\n\n/**\n * The override a catalog gate accepts. A one-line `message` reword or a full `notice` replacement. Accepted by\n * the agnostic catalog gates and, nested per refusal, by {@link RequireRole}. {@link RequirePermissions} and\n * {@link RequireBotPermissions} take `RequirePermissionsOptions` instead.\n *\n * @example\n * ```ts\n * // reword the default refusal\n * OwnerOnly({ message: 'Bot owners only.' });\n * ```\n *\n * @example\n * ```ts\n * // replace the refusal entirely, for example a translated Notice\n * GuildOnly({ notice: new MyTranslatedNotice() });\n * ```\n */\nexport interface GateNoticeOptions {\n /** Reword the default refusal, keeping its embed styling. */\n message?: string;\n /** Replace the default refusal Notice entirely, for full control or a translated copy. */\n notice?: Notice;\n}\n\nexport function pickNotice(options: GateNoticeOptions | undefined, makeDefault: (message?: string) => Notice): Notice {\n return options?.notice ?? makeDefault(options?.message);\n}\n","import { prettify } from '@seedcord/utils';\nimport { PermissionFlagsBits } from 'discord-api-types/v10';\n\n/**\n * The permission flag bits a caller or the bot must hold. Pass the `PermissionFlagsBits` values from\n * `discord-api-types/v10` (or `discord.js`).\n */\nexport type PermissionScope = readonly bigint[];\n\n// permission bit to its prettified human-readable name\nexport const PermissionNames = new Map<bigint, string>(\n Object.entries(PermissionFlagsBits).map(([key, bit]) => [bit, prettify(key)])\n);\n\nconst ADMINISTRATOR = PermissionFlagsBits.Administrator;\n\nfunction nameOf(bit: bigint): string {\n return PermissionNames.get(bit) ?? String(bit);\n}\n\n// discord treats the administrator bit as granting every permission\nfunction holds(held: bigint, bit: bigint): boolean {\n return (held & ADMINISTRATOR) === ADMINISTRATOR || (held & bit) === bit;\n}\n\n/** @internal */\nexport function hasAll(held: bigint, scope: PermissionScope): boolean {\n return scope.every((bit) => holds(held, bit));\n}\n\n/** @internal only reached once hasAll failed, so the administrator bit is absent */\nexport function missingNames(held: bigint, scope: PermissionScope): string[] {\n return scope.reduce<string[]>((names, bit) => {\n if ((held & bit) !== bit) names.push(nameOf(bit));\n return names;\n }, []);\n}\n\n/** @internal */\nexport function presentNames(held: bigint, scope: PermissionScope): string[] {\n return scope.reduce<string[]>((names, bit) => {\n if (holds(held, bit)) names.push(nameOf(bit));\n return names;\n }, []);\n}\n","import { defineGate } from '#gates/Gate';\nimport { MissingPermissions, MissingRole, NotInGuild } from '#notices/index';\nimport { hasAll, missingNames } from '#src/permissions/bits';\n\nimport { pickNotice } from './options';\n\nimport type { Gate, GateContextBase, GuildPermissionsContext } from '#gates/Gate';\nimport type { PermissionScope } from '#src/permissions/bits';\nimport type { GateNoticeOptions } from './options';\n\nexport type { PermissionScope } from '#src/permissions/bits';\nexport { PermissionNames } from '#src/permissions/bits';\n\ninterface PermCheckKind {\n unresolved: string;\n subject: string | null;\n}\n\nconst MEMBER_CHECK: PermCheckKind = {\n unresolved: 'Your server member data could not be resolved. Try again.',\n subject: null\n};\nconst BOT_CHECK: PermCheckKind = {\n unresolved: \"The bot's permissions could not be resolved. Try again.\",\n subject: 'The bot'\n};\n\nfunction refusePermissions(\n held: bigint | null,\n scope: PermissionScope,\n options: RequirePermissionsOptions | undefined,\n guildId: string | null,\n kind: PermCheckKind\n): void {\n if (held === null) {\n throw pickNotice(\n options?.notInGuild,\n (message) => new NotInGuild(message ?? (guildId ? kind.unresolved : undefined))\n );\n }\n if (hasAll(held, scope)) return;\n throw pickNotice(\n options?.missing,\n (message) => new MissingPermissions(message, kind.subject, missingNames(held, scope))\n );\n}\n\n/**\n * Options for {@link RequirePermissions} and {@link RequireBotPermissions}.\n */\nexport interface RequirePermissionsOptions {\n /**\n * The set the check reads. `'channel'` reads the effective channel set the payload carries, what\n * Discord enforces in the invoked channel. `'guild'` reads the base set from roles, available on the\n * gateway transport only.\n *\n * @defaultValue `'channel'`\n */\n in?: 'channel' | 'guild';\n /** Reword or replace the refusal shown when the set is unavailable (outside a guild, or unresolved inside one). */\n notInGuild?: GateNoticeOptions;\n /** Reword or replace the refusal shown when a permission is missing. */\n missing?: GateNoticeOptions;\n}\n\n/**\n * Options for {@link RequireRole}.\n */\nexport interface RequireRoleOptions {\n /** Reword or replace the refusal shown outside a guild. */\n notInGuild?: GateNoticeOptions;\n /** Reword or replace the refusal shown when the caller lacks the role. */\n missingRole?: GateNoticeOptions;\n}\n\n/**\n * Requires the caller to hold every permission in `scope`. Refuses outside a guild first, then when a\n * permission is missing. The Administrator bit passes any scope.\n *\n * The default `'channel'` scope reads the effective channel set the payload carries, what Discord enforces\n * in the invoked channel. The `'guild'` scope reads the base set from roles and requires a\n * {@link GuildPermissionsContext}, so it fits a gateway handler only.\n *\n * @param scope - The permission flag bits the caller must all hold.\n * @param options - Pick the scope with `in`, and override each refusal with `notInGuild` or `missing`.\n *\n * @see the `@Gated` decorator from your transport package\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord-api-types/v10';\n *\n * \\@Gated(RequirePermissions([PermissionFlagsBits.BanMembers]))\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // the base set from roles, on a gateway handler\n * RequirePermissions([PermissionFlagsBits.BanMembers], { in: 'guild' });\n * ```\n */\nexport function RequirePermissions(\n scope: PermissionScope,\n options: RequirePermissionsOptions & { in: 'guild' }\n): Gate<GuildPermissionsContext, 'RequirePermissions'>;\nexport function RequirePermissions(\n scope: PermissionScope,\n options?: RequirePermissionsOptions & { in?: 'channel' }\n): Gate<GateContextBase, 'RequirePermissions'>;\nexport function RequirePermissions(\n scope: PermissionScope,\n options?: RequirePermissionsOptions\n): Gate<GuildPermissionsContext, 'RequirePermissions'> | Gate<GateContextBase, 'RequirePermissions'> {\n if (options?.in === 'guild') {\n return defineGate('RequirePermissions', (ctx: GuildPermissionsContext) => {\n refusePermissions(ctx.memberGuildPermissions, scope, options, ctx.guildId, MEMBER_CHECK);\n });\n }\n return defineGate('RequirePermissions', (ctx: GateContextBase) => {\n refusePermissions(ctx.memberPermissions, scope, options, ctx.guildId, MEMBER_CHECK);\n });\n}\n\n/**\n * Requires the bot to hold every permission in `scope`. Refuses outside a guild first, then when a\n * permission is missing. The Administrator bit passes any scope.\n *\n * The default `'channel'` scope reads the bot's effective channel set (wire `app_permissions`), what\n * Discord enforces in the invoked channel. The `'guild'` scope reads the bot's base set from roles and\n * requires a {@link GuildPermissionsContext}, fitting a gateway handler only. `app_permissions` is\n * absent on gateway events, the channel scope refuses there as unresolved, use `in: 'guild'` on an\n * event handler.\n *\n * @param scope - The permission flag bits the bot must all hold.\n * @param options - Pick the scope with `in`, and override each refusal with `notInGuild` or `missing`.\n *\n * @see the `@Gated` decorator from your transport package\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord-api-types/v10';\n *\n * \\@Gated(RequireBotPermissions([PermissionFlagsBits.ManageMessages]))\n * \\@SlashRoute('purge')\n * class PurgeHandler extends SlashHandler<'purge'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function RequireBotPermissions(\n scope: PermissionScope,\n options: RequirePermissionsOptions & { in: 'guild' }\n): Gate<GuildPermissionsContext, 'RequireBotPermissions'>;\nexport function RequireBotPermissions(\n scope: PermissionScope,\n options?: RequirePermissionsOptions & { in?: 'channel' }\n): Gate<GateContextBase, 'RequireBotPermissions'>;\nexport function RequireBotPermissions(\n scope: PermissionScope,\n options?: RequirePermissionsOptions\n): Gate<GuildPermissionsContext, 'RequireBotPermissions'> | Gate<GateContextBase, 'RequireBotPermissions'> {\n if (options?.in === 'guild') {\n return defineGate('RequireBotPermissions', (ctx: GuildPermissionsContext) => {\n refusePermissions(ctx.appGuildPermissions, scope, options, ctx.guildId, BOT_CHECK);\n });\n }\n return defineGate('RequireBotPermissions', (ctx: GateContextBase) => {\n refusePermissions(ctx.appPermissions, scope, options, ctx.guildId, BOT_CHECK);\n });\n}\n\n/**\n * Requires the caller to hold `roleId`, read from the member's role ids. Refuses outside a guild first,\n * then when the role is missing. Roles are guild-global, so there is no scope dimension.\n *\n * @param roleId - The role snowflake the caller must hold.\n * @param options - Override each refusal, the outside-guild one with `notInGuild` and the missing-role one with `missingRole`.\n *\n * @see the `@Gated` decorator from your transport package\n *\n * @example\n * ```ts\n * \\@Gated(RequireRole('123456789012345678'))\n * \\@SlashRoute('vip')\n * class VipHandler extends SlashHandler<'vip'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function RequireRole(roleId: string, options?: RequireRoleOptions): Gate<GateContextBase, 'RequireRole'> {\n return defineGate('RequireRole', (ctx) => {\n if (!ctx.guildId) throw pickNotice(options?.notInGuild, (message) => new NotInGuild(message));\n if (ctx.memberRoleIds.includes(roleId)) return;\n throw pickNotice(options?.missingRole, (message) => new MissingRole(message, roleId));\n });\n}\n","/**\n * Throw to stop a handler with no reply and no report.\n *\n * The framework boundary catches `Silence` before {@link Notice}, makes zero Discord calls, and stops.\n * Ideally you'd only throw this in `EventHandlers` (or `Gates` for those), because it doesn't make sense to\n * leave the user with no reply for an interaction.\n *\n * @example\n * ```ts\n * import { Silence } from '@seedcord/gateway';\n *\n * // before any reply or defer, drop the interaction with no reply and no report\n * if (await isBlacklisted(interaction.user.id)) throw new Silence('blacklisted user');\n * ```\n */\nexport class Silence extends Error {\n /**\n * @param reason - Optional note written only to a debug log, never shown to the user or reported.\n */\n public constructor(public readonly reason?: string) {\n super(reason ?? 'Silence');\n\n Error.captureStackTrace(this, this.constructor);\n }\n}\n","import { CustomId } from '#customId/CustomId';\n\nimport type { CustomIdField } from '#customId/Field';\n\n// Included in the layout hash so it is fixed per prefix. Reducing it marks every active button as StaleCustomId.\n// @internal\nexport const PAGE_MAX = 1_000_000;\n\n// Discord rejects a message with duplicate custom_ids, and two controls can target the same page (first and\n// prev both hit 0).\n// @internal\nconst SLOT_MAX = 4;\n\n/** Page cursor for a paginator. */\nexport type PageCursor<Prefix extends string> = CustomId<\n Prefix,\n { page: CustomIdField<number>; slot: CustomIdField<number> }\n>;\n\n/** Build the page cursor for a paginator. */\nexport function pageCursor<Prefix extends string>(prefix: Prefix): PageCursor<Prefix> {\n return new CustomId(prefix).int('page', 0, PAGE_MAX).int('slot', 0, SLOT_MAX);\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as Constructor } from "./basic-Dng__Ena.mjs";
|
|
2
|
-
import { E as SubscriptionKey, g as CoreBase, x as Subscriber } from "./Plugin-
|
|
2
|
+
import { E as SubscriptionKey, g as CoreBase, x as Subscriber } from "./Plugin-B6iRzm3g.mjs";
|
|
3
3
|
import "reflect-metadata";
|
|
4
4
|
import { APIMessageTopLevelComponent } from "discord-api-types/v10";
|
|
5
5
|
import { EventFrequency, ReplyFile } from "@seedcord/types";
|
|
@@ -132,4 +132,4 @@ declare abstract class WebhookLog<KeyOfSubscribers extends SubscriptionKey, TCor
|
|
|
132
132
|
declare function WebhookUrl(envKey: string): <HandlerCtor extends Constructor<WebhookLog<SubscriptionKey, CoreBase>>>(constructor: HandlerCtor) => void;
|
|
133
133
|
//#endregion
|
|
134
134
|
export { Subscribe as a, WebhookFile as i, WebhookLog as n, SubscribeOptions as o, WebhookReport as r, WebhookUrl as t };
|
|
135
|
-
//# sourceMappingURL=index-
|
|
135
|
+
//# sourceMappingURL=index-uBwh8r7x.d.mts.map
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { $ as Promisable, C as Gate, D as defineEffectGate, E as RequiredOf, F as ComponentKindBrand, I as ContextMenuKindBrand, K as AnyCustomId, L as SlashRouteBrand, N as AutocompleteRouteBrand, O as defineGate, P as ComponentDefsBrand, Q as RegisterCommand, S as EffectGate, T as GuildPermissionsContext, _t as UserContextMenuRegistry, a as AutocompleteOptions, at as CommandInfo, b as JoinNames, ct as ContextMenuInfo, d as RequirePermissionsOptions, dt as InjectedContextMenuMap, f as RequireRole, ft as OptionKind, g as GateNoticeOptions, gt as MessageContextMenuRegistry, h as PermissionScope, ht as ContextMenuKind, it as RowType, k as BaseReplySender, l as RequireBotPermissions, lt as ContextMenus, mt as SlashOptionRegistry, n as PageCursor, nt as RowComponent, p as RequireRoleOptions, pt as SlashOption, q as CustomId, rt as BuilderType, st as Commands, tt as BuilderComponent, u as RequirePermissions, ut as InjectedCommandMap, w as GateContextBase, x as TwoOrMore, y as IntersectRequired, z as SelectMenuKind } from "./cursor-
|
|
1
|
+
import { $ as Promisable, C as Gate, D as defineEffectGate, E as RequiredOf, F as ComponentKindBrand, I as ContextMenuKindBrand, K as AnyCustomId, L as SlashRouteBrand, N as AutocompleteRouteBrand, O as defineGate, P as ComponentDefsBrand, Q as RegisterCommand, S as EffectGate, T as GuildPermissionsContext, _t as UserContextMenuRegistry, a as AutocompleteOptions, at as CommandInfo, b as JoinNames, ct as ContextMenuInfo, d as RequirePermissionsOptions, dt as InjectedContextMenuMap, f as RequireRole, ft as OptionKind, g as GateNoticeOptions, gt as MessageContextMenuRegistry, h as PermissionScope, ht as ContextMenuKind, it as RowType, k as BaseReplySender, l as RequireBotPermissions, lt as ContextMenus, mt as SlashOptionRegistry, n as PageCursor, nt as RowComponent, p as RequireRoleOptions, pt as SlashOption, q as CustomId, rt as BuilderType, st as Commands, tt as BuilderComponent, u as RequirePermissions, ut as InjectedCommandMap, w as GateContextBase, x as TwoOrMore, y as IntersectRequired, z as SelectMenuKind } from "./cursor-0Dpi07Sj.mjs";
|
|
2
2
|
import { t as Constructor } from "./basic-Dng__Ena.mjs";
|
|
3
|
-
import { C as DispatchOutcome, D as Subscriptions, E as SubscriptionKey, O as Notice, T as SubscriptionData, _ as Bus, g as CoreBase, h as StartupPhase, m as ShutdownPhase, n as Initializeable, w as FaultSource, x as Subscriber } from "./Plugin-
|
|
4
|
-
import { a as Subscribe, i as WebhookFile, n as WebhookLog, o as SubscribeOptions, r as WebhookReport, t as WebhookUrl } from "./index-
|
|
3
|
+
import { C as DispatchOutcome, D as Subscriptions, E as SubscriptionKey, O as Notice, T as SubscriptionData, _ as Bus, g as CoreBase, h as StartupPhase, m as ShutdownPhase, n as Initializeable, w as FaultSource, x as Subscriber } from "./Plugin-B6iRzm3g.mjs";
|
|
4
|
+
import { a as Subscribe, i as WebhookFile, n as WebhookLog, o as SubscribeOptions, r as WebhookReport, t as WebhookUrl } from "./index-uBwh8r7x.mjs";
|
|
5
5
|
import "reflect-metadata";
|
|
6
6
|
import { ActionRowBuilder, ButtonBuilder } from "@discordjs/builders";
|
|
7
7
|
import { Logger } from "@seedcord/logger";
|
|
@@ -280,7 +280,7 @@ declare function or<Gates extends TwoOrMore<Gate<GateContextBase>>>(...args: [..
|
|
|
280
280
|
*
|
|
281
281
|
* @param options - Reword the default refusal with `message`, or replace it with `notice`.
|
|
282
282
|
*
|
|
283
|
-
* @see the `@Gated` decorator from
|
|
283
|
+
* @see the `@Gated` decorator from your transport package
|
|
284
284
|
*
|
|
285
285
|
* @example
|
|
286
286
|
* ```ts
|
|
@@ -307,7 +307,7 @@ declare function OwnerOnly(options?: GateNoticeOptions): Gate<GateContextBase, '
|
|
|
307
307
|
*
|
|
308
308
|
* @param options - Reword the default refusal with `message`, or replace it with `notice`.
|
|
309
309
|
*
|
|
310
|
-
* @see the `@Gated` decorator from
|
|
310
|
+
* @see the `@Gated` decorator from your transport package
|
|
311
311
|
*
|
|
312
312
|
* @example
|
|
313
313
|
* ```ts
|
|
@@ -330,7 +330,7 @@ declare function GuildOnly(options?: GateNoticeOptions): Gate<GateContextBase, '
|
|
|
330
330
|
*
|
|
331
331
|
* @param options - Reword the default refusal with `message`, or replace it with `notice`.
|
|
332
332
|
*
|
|
333
|
-
* @see the `@Gated` decorator from
|
|
333
|
+
* @see the `@Gated` decorator from your transport package
|
|
334
334
|
*
|
|
335
335
|
* @example
|
|
336
336
|
* ```ts
|
|
@@ -401,7 +401,7 @@ interface CooldownOptions {
|
|
|
401
401
|
* @param duration - A number is seconds, and a string is a duration like `30m` or `24h`. An unparseable string throws a **SeedcordTypeError**.
|
|
402
402
|
* @param options - Sets the scope with `per`, the uses per window with `limit`, and the refusal text with `message` or `notice`.
|
|
403
403
|
*
|
|
404
|
-
* @see the `@Gated` decorator from
|
|
404
|
+
* @see the `@Gated` decorator from your transport package
|
|
405
405
|
* @see {@link IRateLimiter}
|
|
406
406
|
*
|
|
407
407
|
* @example
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as WebhookUrl, b as InteractionRoutes, c as Subscriber, f as BuilderComponent, h as CommandMetadataKey, o as Subscribe, p as RowComponent, s as WebhookLog, t as Bus } from "./Bus-DcuUtOEL.mjs";
|
|
2
|
-
import { C as NotInDm, D as defineEffectGate, E as OnCooldown, F as storeInteractionRoute, G as ContextMenus, H as Notice, N as selectMenuRouteOf, O as defineGate, P as storeComponentRoute, R as CustomId, S as NotAllowed, T as NotOwner, V as NoticeCard, W as Commands, a as RequirePermissions, c as hasAll, d as pickNotice, h as runCheck, i as RequireBotPermissions, j as contextMenuRouteOf, k as SelectMenuKind, l as missingNames, m as rollbackCommits, n as pageCursor, o as RequireRole, p as markCommits, r as Silence, t as PAGE_MAX, u as presentNames, v as HasDangerousPermissions, w as NotInGuild, x as NeedsAny, y as MissingPermissions } from "./cursor-
|
|
2
|
+
import { C as NotInDm, D as defineEffectGate, E as OnCooldown, F as storeInteractionRoute, G as ContextMenus, H as Notice, N as selectMenuRouteOf, O as defineGate, P as storeComponentRoute, R as CustomId, S as NotAllowed, T as NotOwner, V as NoticeCard, W as Commands, a as RequirePermissions, c as hasAll, d as pickNotice, h as runCheck, i as RequireBotPermissions, j as contextMenuRouteOf, k as SelectMenuKind, l as missingNames, m as rollbackCommits, n as pageCursor, o as RequireRole, p as markCommits, r as Silence, t as PAGE_MAX, u as presentNames, v as HasDangerousPermissions, w as NotInGuild, x as NeedsAny, y as MissingPermissions } from "./cursor-BRyCNqRV.mjs";
|
|
3
3
|
import { n as StartupPhase, t as ShutdownPhase } from "./phases-BauKJOTT.mjs";
|
|
4
4
|
import "./subscribers-DuHg-bGT.mjs";
|
|
5
5
|
import "reflect-metadata";
|
|
@@ -339,7 +339,7 @@ function or(...args) {
|
|
|
339
339
|
*
|
|
340
340
|
* @param options - Reword the default refusal with `message`, or replace it with `notice`.
|
|
341
341
|
*
|
|
342
|
-
* @see the `@Gated` decorator from
|
|
342
|
+
* @see the `@Gated` decorator from your transport package
|
|
343
343
|
*
|
|
344
344
|
* @example
|
|
345
345
|
* ```ts
|
|
@@ -372,7 +372,7 @@ function OwnerOnly(options) {
|
|
|
372
372
|
*
|
|
373
373
|
* @param options - Reword the default refusal with `message`, or replace it with `notice`.
|
|
374
374
|
*
|
|
375
|
-
* @see the `@Gated` decorator from
|
|
375
|
+
* @see the `@Gated` decorator from your transport package
|
|
376
376
|
*
|
|
377
377
|
* @example
|
|
378
378
|
* ```ts
|
|
@@ -400,7 +400,7 @@ function GuildOnly(options) {
|
|
|
400
400
|
*
|
|
401
401
|
* @param options - Reword the default refusal with `message`, or replace it with `notice`.
|
|
402
402
|
*
|
|
403
|
-
* @see the `@Gated` decorator from
|
|
403
|
+
* @see the `@Gated` decorator from your transport package
|
|
404
404
|
*
|
|
405
405
|
* @example
|
|
406
406
|
* ```ts
|
|
@@ -439,7 +439,7 @@ function scopeValue(ctx, per) {
|
|
|
439
439
|
* @param duration - A number is seconds, and a string is a duration like `30m` or `24h`. An unparseable string throws a **SeedcordTypeError**.
|
|
440
440
|
* @param options - Sets the scope with `per`, the uses per window with `limit`, and the refusal text with `message` or `notice`.
|
|
441
441
|
*
|
|
442
|
-
* @see the `@Gated` decorator from
|
|
442
|
+
* @see the `@Gated` decorator from your transport package
|
|
443
443
|
* @see {@link IRateLimiter}
|
|
444
444
|
*
|
|
445
445
|
* @example
|
|
@@ -858,7 +858,7 @@ var CursorSource = class {
|
|
|
858
858
|
//#endregion
|
|
859
859
|
//#region src/index.ts
|
|
860
860
|
/** Package version */
|
|
861
|
-
const version = "0.2.
|
|
861
|
+
const version = "0.2.1-next.0";
|
|
862
862
|
|
|
863
863
|
//#endregion
|
|
864
864
|
export { ArraySource, AutocompleteRoute, BaseHandler, BuilderComponent, Bus, ButtonRoute, Commands, ContextMenuRoute, ContextMenus, Cooldown, CursorSource, CustomId, DispatchContext, DmOnly, Fault, GuildOnly, ModalRoute, Notice, OwnerOnly, PaginatorBase, RegisterCommand, RepliableHandler, RequireBotPermissions, RequirePermissions, RequireRole, ResolvedEmoji, RowComponent, SelectMenuKind, SelectMenuRoute, ShutdownPhase, Silence, SlashRoute, StartupPhase, Subscribe, Subscriber, WebhookLog, WebhookUrl, and, assertPermissions, defineEffectGate, defineGate, mergeRoles, or, paginate, version };
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/decorators/Command.ts","../src/decorators/routes.ts","../src/dispatch/DispatchContext.ts","../src/handlers/BaseHandler.ts","../src/handlers/RepliableHandler.ts","../src/stops/Fault.ts","../src/gates/combinators.ts","../src/gates/catalog/access.ts","../src/gates/catalog/Cooldown.ts","../src/permissions/assert.ts","../src/permissions/mergeRoles.ts","../src/miscellaneous/emoji.ts","../src/pagination/paginate.ts","../src/pagination/controls.ts","../src/pagination/render.ts","../src/pagination/PaginatorBase.ts","../src/pagination/sources.ts","../src/index.ts"],"sourcesContent":["import 'reflect-metadata';\n\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { CommandMetadataKey } from '#src/metadataKeys';\n\nimport type { BuilderComponent } from '#components/Component';\nimport type { Constructor } from 'type-fest';\n\ntype CommandCtor = Constructor<BuilderComponent<'command' | 'context_menu'>>;\n\ninterface GlobalMeta {\n scope: 'global';\n}\n\ninterface GuildMeta {\n scope: 'guild';\n guilds: string[];\n}\n\nexport type CommandMeta = GlobalMeta | GuildMeta;\n\ntype CommandScope = CommandMeta['scope'];\n\n/**\n * Attaches deployment metadata so the framework registers this command globally or in specific guilds.\n *\n * @decorator\n * @example\n * ```typescript\n * \\@RegisterCommand('global')\n * class PingCommand extends BuilderComponent<'command'> {} // or BuilderComponent<'context_menu'>\n * ```\n */\nexport function RegisterCommand(scope: 'global'): (ctor: CommandCtor) => void;\n\n/**\n * Registers a command for specific guild deployment.\n *\n * @param guilds - Array of guild IDs where the command should be registered\n * @decorator\n * @example\n * ```typescript\n * \\@RegisterCommand('guild', ['123456789'])\n * class AdminCommand extends BuilderComponent<'command'> {} // or BuilderComponent<'context_menu'>\n * ```\n */\nexport function RegisterCommand(scope: 'guild', guilds: string[]): (ctor: CommandCtor) => void;\n\nexport function RegisterCommand(scope: CommandScope, guilds: string[] = []) {\n return (ctor: CommandCtor): void => {\n const existingMeta = Reflect.getOwnMetadata(CommandMetadataKey, ctor) as CommandMeta | undefined;\n if (existingMeta) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandAlreadyRegistered, [\n ctor.name,\n existingMeta.scope,\n scope\n ]);\n }\n\n if (scope === 'global' && guilds.length > 0) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandGlobalWithGuilds);\n }\n\n if (scope === 'guild' && (!Array.isArray(guilds) || guilds.length === 0)) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandGuildWithoutGuilds);\n }\n\n const meta: GlobalMeta | GuildMeta = scope === 'global' ? { scope } : { scope, guilds };\n Reflect.defineMetadata(CommandMetadataKey, meta, ctor);\n };\n}\n","import {\n contextMenuRouteOf,\n selectMenuRouteOf,\n storeComponentRoute,\n storeInteractionRoute\n} from '#decorators/interactionRoutes';\nimport { InteractionRoutes } from '#src/metadataKeys';\n\nimport type { AnyCustomId } from '#customId/CustomId';\nimport type { SelectMenuKind } from '#decorators/interactionRoutes';\nimport type {\n ContextMenuKind,\n MessageContextMenuRegistry,\n UserContextMenuRegistry\n} from '#registries/ContextMenuRegistry';\nimport type { SlashOptionRegistry } from '#registries/SlashOptionRegistry';\nimport type {\n AutocompleteRouteBrand,\n ComponentDefsBrand,\n ComponentKindBrand,\n ContextMenuKindBrand,\n SlashRouteBrand\n} from './brands';\nimport type { ApplicationCommandType } from 'discord-api-types/v10';\nimport type { Constructor } from 'type-fest';\n\ntype ComponentBrand = 'button' | 'modal' | SelectMenuKind;\n\n// phantom brands keep the decorators off transport-specific classes\ntype AnyHandlerCtor = new (...args: any[]) => unknown;\n\ntype SlashRouteOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [SlashRouteBrand]?: infer Route extends keyof SlashOptionRegistry;\n }\n ? Route\n : never;\n\ntype AutocompleteRouteOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [AutocompleteRouteBrand]?: infer Route extends keyof SlashOptionRegistry;\n }\n ? Route\n : never;\n\ntype ContextMenuKindOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [ContextMenuKindBrand]?: infer Kind extends ContextMenuKind;\n }\n ? Kind\n : never;\n\ntype ComponentOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [ComponentKindBrand]?: infer Brand extends ComponentBrand;\n }\n ? Brand\n : never;\n\ntype DefsOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [ComponentDefsBrand]?: infer Defs extends readonly AnyCustomId[];\n }\n ? Defs\n : never;\n\ntype AssertSlashRoute<Route extends keyof SlashOptionRegistry, TCtor extends AnyHandlerCtor> = [Route] extends [\n SlashRouteOf<TCtor>\n]\n ? [SlashRouteOf<TCtor>] extends [Route]\n ? TCtor\n : Constructor<['SlashHandler declares a route the SlashRoute decorator does not list', SlashRouteOf<TCtor>]>\n : Constructor<['SlashRoute does not match the SlashHandler generic', Route]>;\n\ntype AssertAutocompleteRoute<Route extends keyof SlashOptionRegistry, TCtor extends AnyHandlerCtor> = [Route] extends [\n AutocompleteRouteOf<TCtor>\n]\n ? [AutocompleteRouteOf<TCtor>] extends [Route]\n ? TCtor\n : Constructor<\n [\n 'AutocompleteHandler declares a command the AutocompleteRoute decorator does not list',\n AutocompleteRouteOf<TCtor>\n ]\n >\n : Constructor<['AutocompleteRoute does not match the AutocompleteHandler generic', Route]>;\n\ntype AssertContextMenuRoute<Kind extends ContextMenuKind, TCtor extends AnyHandlerCtor> = [Kind] extends [\n ContextMenuKindOf<TCtor>\n]\n ? [ContextMenuKindOf<TCtor>] extends [Kind]\n ? TCtor\n : Constructor<\n [\n 'ContextMenuHandler declares a kind the ContextMenuRoute decorator does not match',\n ContextMenuKindOf<TCtor>\n ]\n >\n : Constructor<['ContextMenuRoute does not match the ContextMenuHandler generic', Kind]>;\n\n// one assignability direction for the defs, a bidirectional check would reject const-inferred readonly tuples\ntype AssertComponentRoute<\n Brand extends ComponentBrand,\n Defs extends readonly AnyCustomId[],\n TCtor extends AnyHandlerCtor\n> = [ComponentOf<TCtor>] extends [Brand]\n ? [Brand] extends [ComponentOf<TCtor>]\n ? [DefsOf<TCtor>] extends [Defs]\n ? TCtor\n : Constructor<['the customId definitions do not match the handler generic', DefsOf<TCtor>]>\n : Constructor<['the decorator does not match the handler kind', ComponentOf<TCtor>]>\n : Constructor<['the decorator does not match the handler kind', ComponentOf<TCtor>]>;\n\ntype NamesFor<Kind extends ContextMenuKind> = Kind extends ApplicationCommandType.User\n ? keyof UserContextMenuRegistry\n : keyof MessageContextMenuRegistry;\n\n/**\n * Routes one or more slash commands to a `SlashHandler`.\n *\n * Pass the same route string(s) as the handler's generic. A single command reads `this.options`, several\n * commands branch with `this.match`. The decorator routes and the generic must match exactly. Listing\n * fewer or more than the handler declares is a compile error. Subcommands use a slash path.\n *\n * @param routes - The route string(s) this handler serves, e.g. `'ban'`, `'ban', 'kick'`, or `'demo/setup'`.\n * @decorator\n * @example\n * ```ts\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * const target = this.options.getUser('target');\n * }\n * }\n * ```\n */\nexport function SlashRoute<const Route extends keyof SlashOptionRegistry>(...routes: Route[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertSlashRoute<Route, TCtor>): void {\n storeInteractionRoute(InteractionRoutes.Slash, routes, constructor);\n };\n}\n\n/**\n * Routes one or more commands' autocomplete to an `AutocompleteHandler`.\n *\n * Pass the same command route string(s) as the handler's generic. One command branches with `this.match`\n * over its autocompletable fields, several commands share one handler whose arms span every command's\n * fields. Listing fewer or more commands than the handler declares is a compile error, since the\n * decorator routes and the generic must match exactly.\n *\n * @param routes - The command route string(s) this handler serves, e.g. `'search'` or `'search', 'find'`.\n * @decorator\n * @example\n * ```ts\n * \\@AutocompleteRoute('search')\n * class SearchAutocomplete extends AutocompleteHandler<'search'> {\n * async execute() {\n * await this.match({ query: (value, respond) => respond([{ name: value, value }]) });\n * }\n * }\n * ```\n */\nexport function AutocompleteRoute<const Route extends keyof SlashOptionRegistry>(...routes: Route[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertAutocompleteRoute<Route, TCtor>): void {\n storeInteractionRoute(InteractionRoutes.Autocomplete, routes, constructor);\n };\n}\n\n/**\n * Routes one or more context-menu commands to a `ContextMenuHandler`.\n *\n * Pass the kind (`ApplicationCommandType.User` or `ApplicationCommandType.Message`) and the command name(s),\n * each checked against that kind's registry. A typo there is a compile error. The handler's generic must\n * declare the same kind, cross-checked both directions. Context menus carry no options, so a multi-name\n * handler reads `this.target` uniformly with no branch.\n *\n * @param kind - The context-menu kind, `ApplicationCommandType.User` or `ApplicationCommandType.Message`.\n * @param names - The command name(s) this handler serves, keyed off the matching registry.\n * @decorator\n * @example\n * ```ts\n * \\@ContextMenuRoute(ApplicationCommandType.User, 'View Profile')\n * class ViewProfile extends ContextMenuHandler<ApplicationCommandType.User> {\n * async execute() {\n * const user = this.target;\n * }\n * }\n * ```\n */\nexport function ContextMenuRoute<const Kind extends ContextMenuKind>(kind: Kind, ...names: NamesFor<Kind>[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertContextMenuRoute<Kind, TCtor>): void {\n storeInteractionRoute(contextMenuRouteOf(kind), names, constructor);\n };\n}\n\n/**\n * Routes button interactions to handler classes.\n *\n * Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's\n * generic. Passing different definitions to the decorator and the generic is a compile error. Routing\n * matches the stable prefix, so a wire minted from an older shape still reaches the handler, where\n * reading this.params throws StaleCustomId and the controller boundary turns it into a reply.\n *\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n */\nexport function ButtonRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertComponentRoute<'button', Defs, TCtor>): void {\n storeComponentRoute(InteractionRoutes.Button, defs, constructor);\n };\n}\n\n/**\n * Routes modal submissions to handler classes.\n *\n * Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's\n * generic. Passing different definitions to the decorator and the generic is a compile error. Routing\n * matches the stable prefix here too, throwing StaleCustomId on read the same as a button route.\n *\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n */\nexport function ModalRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertComponentRoute<'modal', Defs, TCtor>): void {\n storeComponentRoute(InteractionRoutes.Modal, defs, constructor);\n };\n}\n\n/**\n * Routes select menu interactions to handler classes.\n *\n * Pass the select kind and the {@link CustomId} definition(s) this handler decodes. The handler's\n * generic must list the same kind and definitions, or it is a compile error.\n *\n * @param type - Select menu kind from {@link SelectMenuKind}.\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n *\n * @example\n * ```typescript\n * \\@SelectMenuRoute(SelectMenuKind.User, AssignId)\n * class AssignSelect extends SelectMenuHandler<SelectMenuKind.User, [typeof AssignId]> {}\n * ```\n */\nexport function SelectMenuRoute<const Kind extends SelectMenuKind, const Defs extends readonly AnyCustomId[]>(\n type: Kind,\n ...defs: Defs\n) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertComponentRoute<Kind, Defs, TCtor>): void {\n storeComponentRoute(selectMenuRouteOf(type), defs, constructor);\n };\n}\n","/**\n * The per-dispatch bag. Any code can merge fields into it by declaration merging, the\n * same pattern as {@link SlashOptionRegistry}. It stays empty until one does, so `keyof DispatchState` is\n * `never` and the bag is inert.\n */\nexport interface DispatchState {}\n\n/**\n * A typed bag allocated once per interaction dispatch and handed to the handler. The middleware and i18n\n * work reads and writes it through {@link DispatchState}. Today the bag is empty, so it only carries the\n * dispatched `routeId`.\n */\nexport class DispatchContext {\n private readonly state: Partial<DispatchState> = {};\n\n constructor(public readonly routeId: string | null) {}\n\n set<Key extends keyof DispatchState>(key: Key, value: DispatchState[Key]): void {\n this.state[key] = value;\n }\n\n get<Key extends keyof DispatchState>(key: Key): DispatchState[Key] | undefined {\n return this.state[key];\n }\n}\n","import { Logger } from '@seedcord/logger';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { DispatchContext } from '#src/dispatch/DispatchContext';\nimport type { LoggerChannelId } from '@seedcord/types';\n\n/**\n * Base class every transport handler extends. Don't register handlers directly. Use the more specific\n * handler subclasses.\n *\n * @typeParam Event - The event or interaction this handler processes\n * @typeParam TCore - The transport's Core\n */\nexport abstract class BaseHandler<Event, TCore extends CoreBase> {\n protected readonly event: Event;\n protected readonly logger: Logger;\n // absent on event handlers\n protected readonly dispatch?: DispatchContext | undefined;\n\n protected constructor(\n event: Event,\n public readonly core: TCore,\n dispatch?: DispatchContext,\n channel?: LoggerChannelId\n ) {\n this.event = event;\n this.logger = new Logger(this.constructor.name, { channel });\n this.dispatch = dispatch;\n }\n\n /**\n * Holds the main logic of your handler. The dispatcher calls it after the handler's gates pass, so a\n * gate that refuses stops `execute()` from running.\n */\n abstract execute(): Promise<void>;\n}\n","import { BaseHandler } from './BaseHandler';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { BaseReplySender } from '#reply/BaseReplySender';\nimport type { DispatchContext } from '#src/dispatch/DispatchContext';\nimport type { DeferOpts, ReplyResponse, SendOpts } from '@seedcord/types';\n\n/**\n * Shared base the repliable handlers on both transports extend. Defines the reply members over the sender\n * the transport builds.\n *\n * @typeParam Event - The repliable interaction type this handler processes\n * @typeParam TCore - The transport's Core\n * @typeParam TMessage - The transport's created-message lens\n * @typeParam TNative - The transport's own file forms, beyond the portable `ReplyFile`\n * @typeParam TSender - The transport's reply sender\n */\nexport abstract class RepliableHandler<\n Event,\n TCore extends CoreBase,\n TMessage extends { id: string },\n TNative,\n TSender extends BaseReplySender<TMessage, TNative>\n> extends BaseHandler<Event, TCore> {\n protected readonly sender: TSender;\n protected readonly routeId: string;\n\n protected constructor(event: Event, core: TCore, dispatch?: DispatchContext) {\n super(event, core, dispatch, 'interactions');\n this.routeId = dispatch?.routeId ?? this.constructor.name;\n // the override runs before its own field initializers\n this.sender = this.buildSender(event, core, this.routeId);\n }\n\n protected abstract buildSender(event: Event, core: TCore, routeId: string): TSender;\n\n /** @internal The dispatcher's fault boundary replies through the live ack state. */\n public getSender(): TSender {\n return this.sender;\n }\n\n /** Send the initial response, exactly once. */\n protected reply(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.reply(response, opts);\n }\n\n /** Show a \"thinking\" placeholder, then fill it later with {@link edit}. */\n protected defer(opts?: DeferOpts): Promise<void> {\n return this.sender.defer(opts);\n }\n\n /** Send a new message once the interaction is acknowledged. */\n protected followUp(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.followUp(response, opts);\n }\n\n /** Rewrite the initial reply or deferred placeholder. The targeted form rewrites a message a prior send returned. */\n protected edit(response: ReplyResponse<TNative> | string): Promise<TMessage>;\n protected edit(target: TMessage, response: ReplyResponse<TNative> | string): Promise<TMessage>;\n protected edit(\n targetOrResponse: TMessage | ReplyResponse<TNative> | string,\n maybeResponse?: ReplyResponse<TNative> | string\n ): Promise<TMessage> {\n // justified: the overloads narrow targetOrResponse to a response once maybeResponse is absent\n if (maybeResponse === undefined) return this.sender.edit(targetOrResponse as ReplyResponse<TNative> | string);\n // justified: the overloads narrow targetOrResponse to a target message once maybeResponse is defined\n return this.sender.edit(targetOrResponse as TMessage, maybeResponse);\n }\n\n /** Routes to reply, followUp, or edit based on the current ack state. */\n protected send(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.send(response, opts);\n }\n\n /** Delete the initial reply or deferred placeholder. Pass a target to delete a message a prior send returned. */\n protected delete(target?: TMessage): Promise<void> {\n return target === undefined ? this.sender.delete() : this.sender.delete(target);\n }\n}\n","import { Notice } from './Notice';\nimport { NoticeCard } from './NoticeCard';\n\nimport type { RenderContext, ReplyResponse } from '@seedcord/types';\n\n/**\n * A generic fault you throw after catching an error you do not have a specific message for.\n *\n * The user sees a fixed generic reply with the tracking uuid, never the cause. `report` defaults to\n * `true`, so the framework logs it and publishes it to the `handledException` bus. Pass `report: false`\n * to show the generic reply without the bus publish. The original error is stored as the standard\n * `cause`, so the real stack reaches the webhook. When the user should see a real message for a fault,\n * subclass {@link Notice} and write your own `render` instead.\n *\n * The framework also renders this for an unhandled throw, where it points the user at\n * `ctx.developerUsername`.\n *\n * @example\n * ```ts\n * import { Fault } from '@seedcord/gateway';\n *\n * try {\n * await db.write(record);\n * } catch (cause) {\n * // user sees the generic reply with the uuid, and the real error rides along as cause for the webhook\n * throw new Fault({ cause });\n *\n * // pass report: false to show the same reply without publishing to the handledException bus\n * // throw new Fault({ cause, report: false });\n * }\n * ```\n */\nexport class Fault extends Notice {\n public constructor(options?: { cause?: unknown; report?: boolean }) {\n super('A fault occurred', options?.cause === undefined ? undefined : { cause: options.cause });\n this.report = options?.report ?? true;\n }\n\n public render(ctx: RenderContext): ReplyResponse {\n const contact = ctx.developerUsername ?? 'the developer';\n const card = new NoticeCard(\n `Something went wrong. Please reach out to ${contact} with a way to reproduce the error and the following:\\n### UUID: \\`${ctx.uuid}\\``,\n 'Error'\n );\n return { components: [card.component] };\n }\n}\n","import { NeedsAny, NotAllowed } from '#notices/index';\nimport { Fault } from '#stops/Fault';\nimport { Notice } from '#stops/Notice';\n\nimport { markCommits, rollbackCommits, runCheck } from './effects';\nimport { defineGate } from './Gate';\n\nimport type { Gate, GateContextBase, RequiredOf } from './Gate';\nimport type { IntersectRequired, JoinNames, TwoOrMore } from './matching';\n\n/**\n * Runs each gate in order and refuses on the first refusal. Takes two or more arms. The required\n * context is the intersection of the arms, so an event-only and an interaction-only gate cannot be\n * combined.\n *\n * @typeParam Gates - The tuple of two or more gate arms, run left to right.\n * @param gates - The gate arms to run in order, all refused on the first refusal.\n *\n * @see {@link or}\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n *\n * \\@Gated(and(GuildOnly(), RequirePermissions([PermissionFlagsBits.BanMembers])))\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function and<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...gates: Gates\n): Gate<IntersectRequired<Gates> & GateContextBase, JoinNames<Gates, ' & '>>;\nexport function and(...gates: readonly Gate<GateContextBase>[]): Gate<GateContextBase> {\n return defineGate(gates.map((gate) => gate.name).join(' & '), async (ctx) => {\n for (const gate of gates) {\n await runCheck(gate, ctx);\n }\n });\n}\n\n// the caller-supplied refusal when every or arm refuses, replacing the default list or neutral refusal\ninterface OrOptions {\n fail: Notice | ((ctx: GateContextBase) => Notice);\n}\n\n// a gate has a check method, but the options object does not\nfunction isOrOptions(arg: Gate<GateContextBase> | OrOptions): arg is OrOptions {\n return !('check' in arg);\n}\n\n/**\n * Runs each gate in order and passes on the first arm that passes. Takes two or more arms. The\n * required context is the union of the arms. A handler that matches any one arm fits. When every\n * arm refuses it throws the trailing {@link OrOptions} `fail` if given, else an auto list of the\n * arms derived from the summary field, else a default refusal. The trailing options object does not\n * count as an arm.\n *\n * @typeParam Gates - The tuple of two or more gate arms, tried left to right.\n * @param gates - The gate arms to try in order, with an optional trailing {@link OrOptions} object.\n *\n * @see {@link and}\n *\n * @example\n * ```ts\n * \\@Gated(or(OwnerOnly(), RequireRole('123456789012345678')))\n * \\@SlashRoute('admin')\n * class AdminHandler extends SlashHandler<'admin'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function or<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...gates: Gates\n): Gate<RequiredOf<Gates[number]>, JoinNames<Gates, ' | '>>;\n/**\n * @example\n * ```ts\n * // custom refusal when every arm refuses\n * or(OwnerOnly(), RequireRole('123456789012345678'), { fail: new NotAllowedNotice() });\n * ```\n */\nexport function or<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...args: [...Gates, OrOptions]\n): Gate<RequiredOf<Gates[number]>, JoinNames<Gates, ' | '>>;\nexport function or(...args: readonly (Gate<GateContextBase> | OrOptions)[]): Gate<GateContextBase> {\n const last = args.at(-1);\n const options = last !== undefined && isOrOptions(last) ? last : undefined;\n const gates = (options ? args.slice(0, -1) : args) as readonly Gate<GateContextBase>[];\n\n return defineGate(gates.map((gate) => gate.name).join(' | '), async (ctx) => {\n const summaries: string[] = [];\n let everyArmHasSummary = true;\n for (const gate of gates) {\n const mark = markCommits(ctx);\n try {\n await runCheck(gate, ctx);\n return;\n } catch (error) {\n // only a refusal counts as an arm declining. a Fault (even report-false), a Silence, or a raw error stops everything\n if (error instanceof Notice && !(error instanceof Fault) && !error.report) {\n // the arm may have queued an effect's commit before refusing, so drop it before the winner carries it\n rollbackCommits(ctx, mark);\n if (error.summary === undefined) everyArmHasSummary = false;\n else summaries.push(error.summary);\n continue;\n }\n throw error;\n }\n }\n if (options) throw typeof options.fail === 'function' ? options.fail(ctx) : options.fail;\n // the auto-list shows only when every refusal gave a summary, because a partial list would mislead by omission\n if (everyArmHasSummary && summaries.length > 0) throw new NeedsAny(summaries);\n throw new NotAllowed();\n });\n}\n","import { defineGate } from '#gates/Gate';\nimport { NotInDm, NotInGuild, NotOwner } from '#notices/index';\n\nimport { pickNotice } from './options';\n\nimport type { Gate, GateContextBase } from '#gates/Gate';\nimport type { GateNoticeOptions } from './options';\n\n/**\n * Passes only for a user id listed in `config.ownerIds`, else refuses.\n *\n * Agnostic, so it attaches to interaction and event handlers alike. With no `ownerIds` configured it refuses every caller. Pass {@link GateNoticeOptions} to reword or replace the refusal.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\n *\n * @example\n * ```ts\n * \\@Gated(OwnerOnly())\n * \\@SlashRoute('shutdown')\n * class ShutdownHandler extends SlashHandler<'shutdown'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // reword the refusal, keeping the embed styling\n * OwnerOnly({ message: 'Owners only.' });\n * ```\n */\nexport function OwnerOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'OwnerOnly'> {\n return defineGate('OwnerOnly', (ctx) => {\n const owners = ctx.core.config.ownerIds ?? [];\n if (ctx.userId !== null && owners.includes(ctx.userId)) return;\n throw pickNotice(options, (message) => new NotOwner(message));\n });\n}\n\n/**\n * Passes inside a guild, else refuses.\n *\n * Agnostic. Attaches to any handler kind. Often paired with `RequirePermissions` in an {@link and}.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n *\n * \\@Gated(GuildOnly(), RequirePermissions([PermissionFlagsBits.Administrator]))\n * \\@SlashRoute('maintenance')\n * class Maintenance extends SlashHandler<'maintenance'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function GuildOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'GuildOnly'> {\n return defineGate('GuildOnly', (ctx) => {\n if (ctx.guildId) return;\n throw pickNotice(options, (message) => new NotInGuild(message));\n });\n}\n\n/**\n * Passes in a direct message, else refuses.\n *\n * Agnostic, fitting any handler kind. The inverse of {@link GuildOnly}, so combining the two in an {@link and} can never pass.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\n *\n * @example\n * ```ts\n * \\@Gated(DmOnly())\n * \\@SlashRoute('verify')\n * class VerifyHandler extends SlashHandler<'verify'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function DmOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'DmOnly'> {\n return defineGate('DmOnly', (ctx) => {\n if (!ctx.guildId) return;\n throw pickNotice(options, (message) => new NotInDm(message));\n });\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordTypeError } from '@seedcord/errors/internal';\nimport { parseDuration, type ValidDuration } from '@seedcord/utils';\n\nimport { defineEffectGate } from '#gates/Gate';\nimport { OnCooldown } from '#notices/index';\n\nimport type { EffectGate, GateContextBase } from '#gates/Gate';\nimport type { Notice } from '#stops/Notice';\nimport type { EpochMs } from '@seedcord/types';\n\n/**\n * Options for {@link Cooldown}. `per` sets the bucket the window applies to and `limit` the uses allowed per\n * window. `message` rewords the refusal and `notice` replaces it, both receiving the epoch ms the key frees\n * up so the refusal can show the retry time.\n *\n * @example\n * ```ts\n * // one use per channel, rewording the refusal with the retry time\n * Cooldown('10s', {\n * per: 'channel',\n * message: (resetAt) => `Slow down. Try again <t:${Math.round(resetAt / 1000)}:R>.`\n * });\n * ```\n *\n * @example\n * ```ts\n * // five uses per minute, per user\n * Cooldown('1m', { limit: 5 });\n * ```\n */\nexport interface CooldownOptions {\n /**\n * The bucket the cooldown window applies to. 'user' scopes by user ID (falls back to global when the source carries no user id). 'guild' scopes by guild ID (falls back to global if no guild), and 'channel' scopes by channel ID (falls back to global if no channel).\n *\n * @defaultValue `'user'`\n */\n per?: 'user' | 'guild' | 'channel';\n /**\n * Uses allowed inside one window before the gate refuses.\n *\n * @defaultValue `1`\n */\n limit?: number;\n /**\n * Reword the refusal, keeping the standard notice card. Receives the epoch ms the key frees up, to\n * show the retry time with `<t:${Math.round(resetAt / 1000)}:R>`.\n */\n message?: (resetAt: EpochMs) => string;\n /**\n * Replace the refusal Notice entirely, for full control or a translated copy. Receives the epoch ms the\n * key frees up.\n */\n notice?: (resetAt: EpochMs) => Notice;\n}\n\n// off-route ctxs have no route to key on. each Cooldown() call gets its own id to keep unrelated event handlers isolated\nlet anonSeq = 0;\n\nfunction scopeValue(ctx: GateContextBase, per: 'user' | 'guild' | 'channel'): string {\n if (per === 'guild') return ctx.guildId ?? 'global';\n if (per === 'channel') return ctx.channelId ?? 'global';\n return ctx.userId ?? 'global';\n}\n\n/**\n * Allows `limit` uses per window, scoped by `per`. A number `duration` is **seconds**, and a string is\n * a duration like `30m` or `24h`. An unparseable string throws a **SeedcordTypeError** at construction. The\n * slot is charged in commit, only after the whole gate set passes, so a later refusal never burns the cooldown.\n * That split also means two requests racing the same key can both pass before either charges the slot.\n * The key combines the handler's route with the window settings, keeping two different handlers on separate\n * windows. Reword the refusal with {@link CooldownOptions.message} or replace it with {@link CooldownOptions.notice}.\n *\n * @param duration - A number is seconds, and a string is a duration like `30m` or `24h`. An unparseable string throws a **SeedcordTypeError**.\n * @param options - Sets the scope with `per`, the uses per window with `limit`, and the refusal text with `message` or `notice`.\n *\n * @see the `@Gated` decorator from `seedcord`\n * @see {@link IRateLimiter}\n *\n * @example\n * ```ts\n * // a number argument is SECONDS\n * \\@Gated(Cooldown(5))\n * \\@SlashRoute('daily')\n * class DailyHandler extends SlashHandler<'daily'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // a string is a duration, here scoped per guild (the default is per user)\n * Cooldown('30m', { per: 'guild' });\n * ```\n *\n * @example\n * ```ts\n * // a burst, 3 uses per 10 minutes per user, then it refuses until a slot frees\n * \\@Gated(Cooldown('10m', { limit: 3 }))\n * \\@SlashRoute('report')\n * class ReportHandler extends SlashHandler<'report'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function Cooldown(\n duration: number | ValidDuration,\n options?: CooldownOptions\n): EffectGate<GateContextBase, 'Cooldown'> {\n let windowMs: number;\n if (typeof duration === 'number') {\n windowMs = duration * 1000;\n } else {\n const parsed = parseDuration(duration);\n if (parsed === null) throw new SeedcordTypeError(SeedcordErrorCode.GateInvalidCooldownDuration, [duration]);\n windowMs = parsed;\n }\n // refused the same way as an unparseable string, because a zero or negative window would never limit\n if (windowMs <= 0) {\n throw new SeedcordTypeError(SeedcordErrorCode.GateInvalidCooldownDuration, [String(duration)]);\n }\n\n const per = options?.per ?? 'user';\n // exactOptionalPropertyTypes rejects an explicit undefined key\n const window = options?.limit === undefined ? { windowMs } : { windowMs, limit: options.limit };\n const anonId = anonSeq++;\n // routed keys stay stable across restarts, letting a durable store rebuild the same window\n const keyOf = (ctx: GateContextBase): string =>\n `cooldown:${ctx.routeId ?? `anon${anonId}`}:${per}:w${windowMs}:l${options?.limit ?? 1}:${scopeValue(ctx, per)}`;\n\n return defineEffectGate(\n 'Cooldown',\n async (ctx) => {\n const result = await ctx.core.rateLimiter.peek(keyOf(ctx), window);\n if (!result.limited) return;\n if (options?.notice) throw options.notice(result.resetAt);\n throw new OnCooldown(result.resetAt, options?.message?.(result.resetAt));\n },\n async (ctx) => {\n await ctx.core.rateLimiter.charge(keyOf(ctx), window);\n }\n );\n}\n","import { HasDangerousPermissions, MissingPermissions } from '#notices/index';\n\nimport { hasAll, missingNames, presentNames } from './bits';\n\nimport type { Notice } from '#stops/Notice';\nimport type { PermissionScope } from './bits';\n\n/** Replacement notices for the two refusals {@link assertPermissions} raises. */\nexport interface PermissionNoticeOverrides {\n missingNotice?: new (message: string | undefined, subject: string, missingPerms: readonly string[]) => Notice;\n dangerousNotice?: new (message: string | undefined, subject: string, dangerousPerms: readonly string[]) => Notice;\n}\n\n/** The check {@link assertPermissions} runs. */\nexport interface PermissionAssertion extends PermissionNoticeOverrides {\n /** Mention string for who is checked, used as the refusal's subject. */\n subject: string;\n /** The effective permission bitfield the subject holds, computed by the caller. */\n permissions: bigint;\n /** The permission flag bits to check. */\n scope: PermissionScope;\n /** Refuse when the subject holds a scope bit. */\n inverse?: boolean;\n}\n\n/**\n * Refuses when the subject is missing a permission in `scope`, or with `inverse` when it holds one.\n * The Administrator bit passes any scope, and on the inverse arm it reports every bit in `scope`.\n *\n * The caller computes `permissions`, gateway off a discord.js role, member, or channel, and HTTP off the\n * bitfield the interaction payload carries.\n *\n * @throws A {@link Notice} listing the missing or present permissions.\n *\n * @example\n * ```ts\n * import { assertPermissions } from '@seedcord/core';\n * import { PermissionFlagsBits } from 'discord-api-types/v10';\n *\n * // gateway, the bits come off a discord.js member\n * assertPermissions({\n * subject: `<@${member.id}>`,\n * permissions: member.permissions.bitfield,\n * scope: [PermissionFlagsBits.BanMembers]\n * });\n * ```\n *\n * @example\n * ```ts\n * // HTTP, the payload carries the member's bits as a string\n * assertPermissions({\n * subject: `<@${this.event.member.user.id}>`,\n * permissions: BigInt(this.event.member.permissions),\n * scope: [PermissionFlagsBits.ManageMessages]\n * });\n * ```\n *\n * @example\n * ```ts\n * // inverse, refuse a role that carries Administrator\n * assertPermissions({\n * subject: `<@&${role.id}>`,\n * permissions: role.permissions.bitfield,\n * scope: [PermissionFlagsBits.Administrator],\n * inverse: true\n * });\n * ```\n *\n * @example\n * ```ts\n * import { Notice } from '@seedcord/core';\n *\n * // a replacement notice takes the same three arguments the default one does\n * class CannotBan extends Notice {\n * public constructor(\n * message: string | undefined,\n * private readonly subject: string,\n * private readonly missing: readonly string[]\n * ) {\n * super(message ?? 'You cannot ban here.');\n * }\n *\n * public render(): ReplyResponse {\n * return { components: [new BanDenied(this.subject, this.missing).component] };\n * }\n * }\n *\n * assertPermissions({\n * subject: `<@${member.id}>`,\n * permissions: member.permissions.bitfield,\n * scope: [PermissionFlagsBits.BanMembers],\n * missingNotice: CannotBan\n * });\n * ```\n */\nexport function assertPermissions(check: PermissionAssertion): void {\n const { subject, permissions, scope, inverse = false, missingNotice, dangerousNotice } = check;\n\n if (inverse) {\n const present = presentNames(permissions, scope);\n if (present.length === 0) return;\n const Dangerous = dangerousNotice ?? HasDangerousPermissions;\n throw new Dangerous(undefined, subject, present);\n }\n\n if (hasAll(permissions, scope)) return;\n const Missing = missingNotice ?? MissingPermissions;\n throw new Missing(undefined, subject, missingNames(permissions, scope));\n}\n","/**\n * The role ids a member holds after adding and removing the given sets. Removals win over additions.\n *\n * This does not write the roles. Apply the result with `member.roles.set()` on gateway, or PATCH the member over HTTP.\n *\n * @param current - The role ids the member holds.\n * @param add - The role ids to add.\n * @param remove - The role ids to remove.\n * @returns The merged role ids.\n *\n * @example\n * ```ts\n * import { mergeRoles } from '@seedcord/core';\n *\n * // gateway\n * const ids = mergeRoles(member.roles.cache.map((role) => role.id), ['123'], ['456']);\n * await member.roles.set(ids);\n * ```\n */\nexport function mergeRoles(current: readonly string[], add: readonly string[], remove: readonly string[]): string[] {\n return [...new Set(current).union(new Set(add)).difference(new Set(remove))];\n}\n","import type { APIMessageComponentEmoji } from 'discord-api-types/v10';\n\n/**\n * A resolved custom emoji. Renders as `<:name:id>` in message content, or `<a:name:id>` when animated,\n * and passes straight to a builder's `setEmoji`.\n */\n// setEmoji in @discordjs/builders rejects any own key past these three, scanning with Object.entries\nexport class ResolvedEmoji implements APIMessageComponentEmoji {\n constructor(\n public readonly name: string,\n public readonly id: string,\n public readonly animated = false\n ) {}\n\n public toString(): string {\n return `<${this.animated ? 'a' : ''}:${this.name}:${this.id}>`;\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport type { PageView } from './PageView';\n\n/**\n * Pure page math, usable headless. Clamps `page` into range and slices the window.\n *\n * @param items - The full list to page over.\n * @param page - The requested zero-based page, clamped into `[0, totalPages - 1]`.\n * @param perPage - The page size. Must be a positive integer.\n * @returns The sliced {@link PageView}, with `totalPages` always known.\n * @throws SeedcordRangeError when `perPage` is not a positive integer.\n */\nexport function paginate<Item>(items: readonly Item[], page: number, perPage: number): PageView<Item> {\n if (!Number.isSafeInteger(perPage) || perPage <= 0) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationInvalidPerPage, [perPage]);\n }\n\n const totalPages = Math.max(1, Math.ceil(items.length / perPage));\n const clamped = Math.min(Math.max(Math.trunc(page), 0), totalPages - 1);\n const start = clamped * perPage;\n\n return {\n items: items.slice(start, start + perPage),\n page: clamped,\n perPage,\n totalPages,\n hasPrev: clamped > 0,\n hasNext: clamped < totalPages - 1\n };\n}\n","import { ActionRowBuilder, ButtonBuilder } from '@discordjs/builders';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError, SeedcordTypeError } from '@seedcord/errors/internal';\nimport { ButtonStyle } from 'discord-api-types/v10';\n\nimport { PAGE_MAX } from '#pagination/cursor';\n\nimport type { PageCursor } from '#pagination/cursor';\nimport type { PageView } from '#pagination/PageView';\nimport type { APIMessageComponentEmoji } from 'discord-api-types/v10';\n\n/** The five built-in nav controls. */\nexport type ControlKey = 'first' | 'prev' | 'indicator' | 'next' | 'last';\n\n// Link and Premium have no custom_id, which un-routes a control.\ntype CustomIdStyle = ButtonStyle.Primary | ButtonStyle.Secondary | ButtonStyle.Success | ButtonStyle.Danger;\n\n/** Cosmetic overrides for a control button. `style` excludes Link and Premium, which would un-route it. */\nexport interface ControlCosmetics {\n label?: string;\n style?: CustomIdStyle;\n emoji?: APIMessageComponentEmoji;\n}\n\n/** The controls passed to `render`. */\nexport interface PaginatorControls {\n /**\n * A fresh `ButtonBuilder` for one control, already stamped with its target page and disabled-at-bounds\n * state. Call only cosmetic setters on it, because a `setCustomId` or `setStyle(Link)` un-routes it.\n */\n button(key: ControlKey, cosmetics?: ControlCosmetics): ButtonBuilder;\n /**\n * Assemble an action row of the chosen controls, in order. Throws on an empty set, more than five\n * controls, or a duplicate.\n */\n row(...keys: ControlKey[]): ActionRowBuilder<ButtonBuilder>;\n}\n\nconst DEFAULT_LABEL: Record<ControlKey, string> = {\n first: 'First',\n prev: 'Prev',\n indicator: '',\n next: 'Next',\n last: 'Last'\n};\n\n// a distinct slot keeps two controls on the same page off the same id. 0-4 is the cursor's SLOT_MAX.\nconst CONTROL_SLOT: Record<ControlKey, number> = {\n first: 0,\n prev: 1,\n indicator: 2,\n next: 3,\n last: 4\n};\n\nconst MAX_BUTTONS_PER_ROW = 5;\n\nexport class Controls implements PaginatorControls {\n constructor(\n private readonly cursor: PageCursor<string>,\n private readonly view: PageView<unknown>\n ) {}\n\n button(key: ControlKey, cosmetics?: ControlCosmetics): ButtonBuilder {\n const { target, disabled } = this.navState(key);\n\n // an emoji with no explicit label makes an icon-only button. the indicator always shows its page text.\n const defaultLabel = key === 'indicator' ? this.indicatorText() : DEFAULT_LABEL[key];\n const label = cosmetics?.label ?? (key === 'indicator' || !cosmetics?.emoji ? defaultLabel : undefined);\n\n const button = new ButtonBuilder()\n // an enormous list could push last/next past PAGE_MAX, where encode throws.\n .setCustomId(this.cursor.encode({ page: Math.min(Math.max(0, target), PAGE_MAX), slot: CONTROL_SLOT[key] }))\n .setStyle(cosmetics?.style ?? ButtonStyle.Secondary)\n .setDisabled(disabled);\n if (label !== undefined) button.setLabel(label);\n if (cosmetics?.emoji) button.setEmoji(cosmetics.emoji);\n return button;\n }\n\n private navState(key: ControlKey): { target: number; disabled: boolean } {\n const { page, totalPages, hasPrev, hasNext } = this.view;\n const knownTotal = totalPages !== undefined;\n const target = {\n first: 0,\n prev: page - 1,\n indicator: page,\n next: page + 1,\n last: knownTotal ? totalPages - 1 : page\n }[key];\n // past PAGE_MAX the encoded page would clamp to a wrong one\n const disabled = {\n first: !hasPrev,\n prev: !hasPrev,\n indicator: true,\n next: !hasNext || page + 1 > PAGE_MAX,\n last: !hasNext || !knownTotal || totalPages - 1 > PAGE_MAX\n }[key];\n return { target, disabled };\n }\n\n row(...keys: ControlKey[]): ActionRowBuilder<ButtonBuilder> {\n if (keys.length === 0) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationEmptyControls);\n }\n if (keys.length > MAX_BUTTONS_PER_ROW) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationTooManyControls, [keys.length]);\n }\n // repeating a control reuses its slot and page, so the custom_ids collide and Discord rejects the message.\n const seen = new Set<ControlKey>();\n for (const key of keys) {\n if (seen.has(key)) throw new SeedcordTypeError(SeedcordErrorCode.PaginationDuplicateControls, [key]);\n seen.add(key);\n }\n return new ActionRowBuilder<ButtonBuilder>().addComponents(keys.map((key) => this.button(key)));\n }\n\n private indicatorText(): string {\n const { page, totalPages } = this.view;\n return totalPages === undefined ? `Page ${page + 1}` : `Page ${page + 1} of ${totalPages}`;\n }\n}\n","import { TextDisplayBuilder } from '@discordjs/builders';\n\nimport { BuilderComponent } from '#components/Component';\nimport { Controls } from '#pagination/controls';\n\nimport type { ControlKey, PaginatorControls } from '#pagination/controls';\nimport type { PageCursor } from '#pagination/cursor';\nimport type { PageView } from '#pagination/PageView';\nimport type { ButtonBuilder, ActionRowBuilder } from '@discordjs/builders';\nimport type { ReplyResponse, V2Component } from '@seedcord/types';\n\n/** What `renderItem` returns for one item, a text line or a section. */\nexport type ItemRender<Item> = (item: Item, index: number) => string | BuilderComponent<'section'>;\n\ntype Renderable = string | V2Component[] | ReplyResponse;\n\n/** A full-page render override. */\nexport type PageRender<Item> = (view: PageView<Item>, controls: PaginatorControls) => Renderable;\n\n// subclassed because BuilderComponent.instance is protected\nclass PageContainer<Item> extends BuilderComponent<'container'> {\n constructor(view: PageView<Item>, renderItem: ItemRender<Item>, controlRow: ActionRowBuilder<ButtonBuilder>) {\n super('container');\n const base = view.page * view.perPage;\n let lines: string[] = [];\n const flush = (): void => {\n if (lines.length === 0) return;\n this.instance.addTextDisplayComponents(new TextDisplayBuilder().setContent(lines.join('\\n')));\n lines = [];\n };\n view.items.forEach((item, offset) => {\n const rendered = renderItem(item, base + offset);\n if (typeof rendered === 'string') {\n lines.push(rendered);\n return;\n }\n flush();\n this.instance.addSectionComponents(rendered.component);\n });\n flush();\n this.instance.addActionRowComponents(controlRow);\n }\n}\n\nfunction toReplyResponse(renderable: Renderable): ReplyResponse {\n if (typeof renderable === 'string') return { components: [new TextDisplayBuilder().setContent(renderable)] };\n if (Array.isArray(renderable)) return { components: renderable };\n return renderable;\n}\n\nconst ARRAY_KEYS: ControlKey[] = ['first', 'prev', 'indicator', 'next', 'last'];\nconst CURSOR_KEYS: ControlKey[] = ['prev', 'indicator', 'next'];\n\n// a render override builds the whole tree, or the default container lists the items and appends\n// the controls (all five for a known total, prev/indicator/next for a cursor source)\nexport function renderPage<Item>(\n view: PageView<Item>,\n cursor: PageCursor<string>,\n config: { renderItem?: ItemRender<Item>; render?: PageRender<Item> }\n): ReplyResponse {\n const controls = new Controls(cursor, view);\n if (config.render) return toReplyResponse(config.render(view, controls));\n\n const renderItem = config.renderItem ?? String;\n const row = controls.row(...(view.totalPages === undefined ? CURSOR_KEYS : ARRAY_KEYS));\n return { components: [new PageContainer(view, renderItem, row).component] };\n}\n","import { pageCursor } from '#pagination/cursor';\nimport { renderPage } from '#pagination/render';\n\nimport type { PageCursor } from '#pagination/cursor';\nimport type { ItemRender, PageRender } from '#pagination/render';\nimport type { PageSource } from '#pagination/sources';\nimport type { ReplyResponse } from '@seedcord/types';\n\n/**\n * The transport-agnostic paginator configuration. Each transport adds its own handler wiring on top.\n *\n * @typeParam Item - The item type, inferred from the source.\n * @typeParam Prefix - The route prefix, inferred from `prefix`.\n * @typeParam Ctx - The transport's page context.\n */\nexport interface PaginatorConfig<Item, Prefix extends string, Ctx> {\n /** The route prefix used to build the page cursor on the nav buttons. */\n prefix: Prefix;\n source: PageSource<Item, Ctx>;\n /** Render one item, `index` is its absolute position across pages. Ignored when `render` is set. */\n renderItem?: ItemRender<Item>;\n /** Take over the whole page tree. Receives the page data and the controls factory. */\n render?: PageRender<Item>;\n /**\n * Whether the first page is ephemeral.\n *\n * @defaultValue `false`\n */\n ephemeral?: boolean;\n}\n\n/**\n * Holds a paginator's cursor and renders one page. Each transport extends this to add the nav handler and\n * the method that sends the first page.\n *\n * @typeParam Item - The item type, inferred from the source.\n * @typeParam Prefix - The route prefix, inferred from `config.prefix`.\n * @typeParam Ctx - The transport's page context.\n */\nexport abstract class PaginatorBase<Item, Prefix extends string, Ctx> {\n /** The page cursor, pass it to your `@ButtonRoute`. */\n public readonly cursor: PageCursor<Prefix>;\n\n protected readonly config: PaginatorConfig<Item, Prefix, Ctx>;\n\n protected constructor(config: PaginatorConfig<Item, Prefix, Ctx>) {\n this.cursor = pageCursor(config.prefix);\n this.config = config;\n }\n\n /** Render a page as a {@link ReplyResponse}. To post it elsewhere, add `flags: MessageFlags.IsComponentsV2`. */\n async page(ctx: Ctx, n: number): Promise<ReplyResponse> {\n const view = await this.config.source.page(ctx, n);\n return renderPage(view, this.cursor, this.config);\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport { paginate } from '#pagination/paginate';\n\nimport type { PageView } from '#pagination/PageView';\nimport type { Promisable } from 'type-fest';\n\nconst DEFAULT_PER_PAGE = 10;\n\n/**\n * The one method a paginator calls on a source, once per click. Implement it to supply a custom source.\n *\n * @typeParam Item - The item type the source pages over.\n * @typeParam Ctx - The transport's page context, handed to the loader.\n */\nexport interface PageSource<Item, Ctx> {\n page(ctx: Ctx, n: number): Promise<PageView<Item>>;\n}\n\nfunction perPageOf(opts?: { perPage?: number }): number {\n const perPage = opts?.perPage ?? DEFAULT_PER_PAGE;\n if (!Number.isSafeInteger(perPage) || perPage <= 0) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationInvalidPerPage, [perPage]);\n }\n return perPage;\n}\n\n/**\n * A source for a bounded list you can load whole. It loads the full list on every click, then slices the\n * page via {@link paginate}, so the real total is known (a real last button, \"Page X of Y\"). Cache inside\n * your loader if the load is expensive.\n *\n * @typeParam Item - The item type, inferred from the loader's return.\n * @typeParam Ctx - The transport's page context. Each transport exports a subclass that fixes it.\n */\nexport class ArraySource<Item, Ctx> implements PageSource<Item, Ctx> {\n private readonly perPage: number;\n\n constructor(\n private readonly load: (ctx: Ctx) => Promisable<readonly Item[]>,\n opts?: { perPage?: number }\n ) {\n this.perPage = perPageOf(opts);\n }\n\n async page(ctx: Ctx, n: number): Promise<PageView<Item>> {\n return paginate(await this.load(ctx), n, this.perPage);\n }\n}\n\n/**\n * A source for a large or unknown-length set you fetch one page at a time (SQL LIMIT/OFFSET, a paged API).\n * The fetcher receives the page index and the page size and reports whether a next page exists. A cursor\n * source has no cheap total, so `totalPages` is undefined, the last button is omitted, and the indicator\n * reads \"Page X\".\n *\n * @typeParam Item - The item type, inferred from the fetcher's slice.\n * @typeParam Ctx - The transport's page context. Each transport exports a subclass that fixes it.\n */\nexport class CursorSource<Item, Ctx> implements PageSource<Item, Ctx> {\n private readonly perPage: number;\n\n constructor(\n private readonly fetch: (\n ctx: Ctx,\n page: number,\n perPage: number\n ) => Promisable<{ items: readonly Item[]; hasNext: boolean }>,\n opts?: { perPage?: number }\n ) {\n this.perPage = perPageOf(opts);\n }\n\n async page(ctx: Ctx, n: number): Promise<PageView<Item>> {\n const page = Math.max(0, Math.trunc(n));\n const { items, hasNext } = await this.fetch(ctx, page, this.perPage);\n return { items: [...items], page, perPage: this.perPage, hasPrev: page > 0, hasNext };\n }\n}\n","import 'reflect-metadata';\n\nexport type * from '#registries/ContextMenuRegistry';\nexport type * from '#registries/SlashOptionRegistry';\n\nexport { Commands, ContextMenus } from '#src/commands/CommandInjector';\nexport type {\n CommandInfo,\n ContextMenuInfo,\n InjectedCommandMap,\n InjectedContextMenuMap\n} from '#src/commands/CommandInjector';\n\nexport { RegisterCommand } from '#decorators/Command';\nexport { SelectMenuKind } from '#decorators/interactionRoutes';\nexport {\n AutocompleteRoute,\n ButtonRoute,\n ContextMenuRoute,\n ModalRoute,\n SelectMenuRoute,\n SlashRoute\n} from '#decorators/routes';\n\nexport { DispatchContext } from '#src/dispatch/DispatchContext';\nexport type { DispatchState } from '#src/dispatch/DispatchContext';\n\nexport { BaseHandler } from '#src/handlers/BaseHandler';\nexport { RepliableHandler } from '#src/handlers/RepliableHandler';\n\nexport type { CoreBase } from '#interfaces/CoreBase';\n\nexport type { Initializeable } from '#src/plugin/Plugin';\n\nexport { ShutdownPhase, StartupPhase } from '#src/lifecycle/phases';\n\nexport { defineEffectGate, defineGate } from '#gates/Gate';\nexport type { EffectGate, Gate, GateContextBase, GuildPermissionsContext, RequiredOf } from '#gates/Gate';\nexport { and, or } from '#gates/combinators';\nexport { DmOnly, GuildOnly, OwnerOnly } from '#gates/catalog/access';\nexport { Cooldown, type CooldownOptions } from '#gates/catalog/Cooldown';\nexport { RequireBotPermissions, RequirePermissions, RequireRole } from '#gates/catalog/permissions';\nexport type { PermissionScope, RequirePermissionsOptions, RequireRoleOptions } from '#gates/catalog/permissions';\nexport type { GateNoticeOptions } from '#gates/catalog/options';\n\nexport { assertPermissions } from '#src/permissions/assert';\nexport type { PermissionAssertion, PermissionNoticeOverrides } from '#src/permissions/assert';\nexport { mergeRoles } from '#src/permissions/mergeRoles';\n\nexport { BuilderComponent, RowComponent } from '#components/Component';\nexport { type RowType, type BuilderType } from '#components/builderTypes';\n\nexport { Notice } from '#stops/Notice';\nexport { Fault } from '#stops/Fault';\nexport { Silence } from '#stops/Silence';\n\nexport { CustomId } from '#customId/CustomId';\n\nexport { ResolvedEmoji } from '#src/miscellaneous/emoji';\n\nexport type { AutocompleteOptions } from '#inputs/AutocompleteOptions';\n\nexport { paginate } from '#pagination/paginate';\nexport { type PageView } from '#pagination/PageView';\nexport { PaginatorBase } from '#pagination/PaginatorBase';\nexport type { PaginatorConfig } from '#pagination/PaginatorBase';\nexport { ArraySource, CursorSource } from '#pagination/sources';\nexport type { PageSource } from '#pagination/sources';\nexport type { ControlCosmetics, ControlKey, PaginatorControls } from '#pagination/controls';\nexport type { ItemRender, PageRender } from '#pagination/render';\n\nexport { Bus, Subscribe, Subscriber, WebhookLog, WebhookUrl } from '#subscribers/index';\nexport type {\n DispatchOutcome,\n FaultSource,\n SubscribeOptions,\n Subscriptions,\n SubscriptionData,\n SubscriptionKey,\n WebhookFile,\n WebhookReport\n} from '#subscribers/index';\n\n/** Package version */\nexport const version = process.env.PACKAGE_VERSION ?? '0.0.0';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/decorators/Command.ts","../src/decorators/routes.ts","../src/dispatch/DispatchContext.ts","../src/handlers/BaseHandler.ts","../src/handlers/RepliableHandler.ts","../src/stops/Fault.ts","../src/gates/combinators.ts","../src/gates/catalog/access.ts","../src/gates/catalog/Cooldown.ts","../src/permissions/assert.ts","../src/permissions/mergeRoles.ts","../src/miscellaneous/emoji.ts","../src/pagination/paginate.ts","../src/pagination/controls.ts","../src/pagination/render.ts","../src/pagination/PaginatorBase.ts","../src/pagination/sources.ts","../src/index.ts"],"sourcesContent":["import 'reflect-metadata';\n\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport { CommandMetadataKey } from '#src/metadataKeys';\n\nimport type { BuilderComponent } from '#components/Component';\nimport type { Constructor } from 'type-fest';\n\ntype CommandCtor = Constructor<BuilderComponent<'command' | 'context_menu'>>;\n\ninterface GlobalMeta {\n scope: 'global';\n}\n\ninterface GuildMeta {\n scope: 'guild';\n guilds: string[];\n}\n\nexport type CommandMeta = GlobalMeta | GuildMeta;\n\ntype CommandScope = CommandMeta['scope'];\n\n/**\n * Attaches deployment metadata so the framework registers this command globally or in specific guilds.\n *\n * @decorator\n * @example\n * ```typescript\n * \\@RegisterCommand('global')\n * class PingCommand extends BuilderComponent<'command'> {} // or BuilderComponent<'context_menu'>\n * ```\n */\nexport function RegisterCommand(scope: 'global'): (ctor: CommandCtor) => void;\n\n/**\n * Registers a command for specific guild deployment.\n *\n * @param guilds - Array of guild IDs where the command should be registered\n * @decorator\n * @example\n * ```typescript\n * \\@RegisterCommand('guild', ['123456789'])\n * class AdminCommand extends BuilderComponent<'command'> {} // or BuilderComponent<'context_menu'>\n * ```\n */\nexport function RegisterCommand(scope: 'guild', guilds: string[]): (ctor: CommandCtor) => void;\n\nexport function RegisterCommand(scope: CommandScope, guilds: string[] = []) {\n return (ctor: CommandCtor): void => {\n const existingMeta = Reflect.getOwnMetadata(CommandMetadataKey, ctor) as CommandMeta | undefined;\n if (existingMeta) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandAlreadyRegistered, [\n ctor.name,\n existingMeta.scope,\n scope\n ]);\n }\n\n if (scope === 'global' && guilds.length > 0) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandGlobalWithGuilds);\n }\n\n if (scope === 'guild' && (!Array.isArray(guilds) || guilds.length === 0)) {\n throw new SeedcordError(SeedcordErrorCode.DecoratorCommandGuildWithoutGuilds);\n }\n\n const meta: GlobalMeta | GuildMeta = scope === 'global' ? { scope } : { scope, guilds };\n Reflect.defineMetadata(CommandMetadataKey, meta, ctor);\n };\n}\n","import {\n contextMenuRouteOf,\n selectMenuRouteOf,\n storeComponentRoute,\n storeInteractionRoute\n} from '#decorators/interactionRoutes';\nimport { InteractionRoutes } from '#src/metadataKeys';\n\nimport type { AnyCustomId } from '#customId/CustomId';\nimport type { SelectMenuKind } from '#decorators/interactionRoutes';\nimport type {\n ContextMenuKind,\n MessageContextMenuRegistry,\n UserContextMenuRegistry\n} from '#registries/ContextMenuRegistry';\nimport type { SlashOptionRegistry } from '#registries/SlashOptionRegistry';\nimport type {\n AutocompleteRouteBrand,\n ComponentDefsBrand,\n ComponentKindBrand,\n ContextMenuKindBrand,\n SlashRouteBrand\n} from './brands';\nimport type { ApplicationCommandType } from 'discord-api-types/v10';\nimport type { Constructor } from 'type-fest';\n\ntype ComponentBrand = 'button' | 'modal' | SelectMenuKind;\n\n// phantom brands keep the decorators off transport-specific classes\ntype AnyHandlerCtor = new (...args: any[]) => unknown;\n\ntype SlashRouteOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [SlashRouteBrand]?: infer Route extends keyof SlashOptionRegistry;\n }\n ? Route\n : never;\n\ntype AutocompleteRouteOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [AutocompleteRouteBrand]?: infer Route extends keyof SlashOptionRegistry;\n }\n ? Route\n : never;\n\ntype ContextMenuKindOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [ContextMenuKindBrand]?: infer Kind extends ContextMenuKind;\n }\n ? Kind\n : never;\n\ntype ComponentOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [ComponentKindBrand]?: infer Brand extends ComponentBrand;\n }\n ? Brand\n : never;\n\ntype DefsOf<TCtor extends AnyHandlerCtor> =\n InstanceType<TCtor> extends {\n [ComponentDefsBrand]?: infer Defs extends readonly AnyCustomId[];\n }\n ? Defs\n : never;\n\ntype AssertSlashRoute<Route extends keyof SlashOptionRegistry, TCtor extends AnyHandlerCtor> = [Route] extends [\n SlashRouteOf<TCtor>\n]\n ? [SlashRouteOf<TCtor>] extends [Route]\n ? TCtor\n : Constructor<['SlashHandler declares a route the SlashRoute decorator does not list', SlashRouteOf<TCtor>]>\n : Constructor<['SlashRoute does not match the SlashHandler generic', Route]>;\n\ntype AssertAutocompleteRoute<Route extends keyof SlashOptionRegistry, TCtor extends AnyHandlerCtor> = [Route] extends [\n AutocompleteRouteOf<TCtor>\n]\n ? [AutocompleteRouteOf<TCtor>] extends [Route]\n ? TCtor\n : Constructor<\n [\n 'AutocompleteHandler declares a command the AutocompleteRoute decorator does not list',\n AutocompleteRouteOf<TCtor>\n ]\n >\n : Constructor<['AutocompleteRoute does not match the AutocompleteHandler generic', Route]>;\n\ntype AssertContextMenuRoute<Kind extends ContextMenuKind, TCtor extends AnyHandlerCtor> = [Kind] extends [\n ContextMenuKindOf<TCtor>\n]\n ? [ContextMenuKindOf<TCtor>] extends [Kind]\n ? TCtor\n : Constructor<\n [\n 'ContextMenuHandler declares a kind the ContextMenuRoute decorator does not match',\n ContextMenuKindOf<TCtor>\n ]\n >\n : Constructor<['ContextMenuRoute does not match the ContextMenuHandler generic', Kind]>;\n\n// one assignability direction for the defs, a bidirectional check would reject const-inferred readonly tuples\ntype AssertComponentRoute<\n Brand extends ComponentBrand,\n Defs extends readonly AnyCustomId[],\n TCtor extends AnyHandlerCtor\n> = [ComponentOf<TCtor>] extends [Brand]\n ? [Brand] extends [ComponentOf<TCtor>]\n ? [DefsOf<TCtor>] extends [Defs]\n ? TCtor\n : Constructor<['the customId definitions do not match the handler generic', DefsOf<TCtor>]>\n : Constructor<['the decorator does not match the handler kind', ComponentOf<TCtor>]>\n : Constructor<['the decorator does not match the handler kind', ComponentOf<TCtor>]>;\n\ntype NamesFor<Kind extends ContextMenuKind> = Kind extends ApplicationCommandType.User\n ? keyof UserContextMenuRegistry\n : keyof MessageContextMenuRegistry;\n\n/**\n * Routes one or more slash commands to a `SlashHandler`.\n *\n * Pass the same route string(s) as the handler's generic. A single command reads `this.options`, several\n * commands branch with `this.match`. The decorator routes and the generic must match exactly. Listing\n * fewer or more than the handler declares is a compile error. Subcommands use a slash path.\n *\n * @param routes - The route string(s) this handler serves, e.g. `'ban'`, `'ban', 'kick'`, or `'demo/setup'`.\n * @decorator\n * @example\n * ```ts\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * const target = this.options.getUser('target');\n * }\n * }\n * ```\n */\nexport function SlashRoute<const Route extends keyof SlashOptionRegistry>(...routes: Route[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertSlashRoute<Route, TCtor>): void {\n storeInteractionRoute(InteractionRoutes.Slash, routes, constructor);\n };\n}\n\n/**\n * Routes one or more commands' autocomplete to an `AutocompleteHandler`.\n *\n * Pass the same command route string(s) as the handler's generic. One command branches with `this.match`\n * over its autocompletable fields, several commands share one handler whose arms span every command's\n * fields. Listing fewer or more commands than the handler declares is a compile error, since the\n * decorator routes and the generic must match exactly.\n *\n * @param routes - The command route string(s) this handler serves, e.g. `'search'` or `'search', 'find'`.\n * @decorator\n * @example\n * ```ts\n * \\@AutocompleteRoute('search')\n * class SearchAutocomplete extends AutocompleteHandler<'search'> {\n * async execute() {\n * await this.match({ query: (value, respond) => respond([{ name: value, value }]) });\n * }\n * }\n * ```\n */\nexport function AutocompleteRoute<const Route extends keyof SlashOptionRegistry>(...routes: Route[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertAutocompleteRoute<Route, TCtor>): void {\n storeInteractionRoute(InteractionRoutes.Autocomplete, routes, constructor);\n };\n}\n\n/**\n * Routes one or more context-menu commands to a `ContextMenuHandler`.\n *\n * Pass the kind (`ApplicationCommandType.User` or `ApplicationCommandType.Message`) and the command name(s),\n * each checked against that kind's registry. A typo there is a compile error. The handler's generic must\n * declare the same kind, cross-checked both directions. Context menus carry no options, so a multi-name\n * handler reads `this.target` uniformly with no branch.\n *\n * @param kind - The context-menu kind, `ApplicationCommandType.User` or `ApplicationCommandType.Message`.\n * @param names - The command name(s) this handler serves, keyed off the matching registry.\n * @decorator\n * @example\n * ```ts\n * \\@ContextMenuRoute(ApplicationCommandType.User, 'View Profile')\n * class ViewProfile extends ContextMenuHandler<ApplicationCommandType.User> {\n * async execute() {\n * const user = this.target;\n * }\n * }\n * ```\n */\nexport function ContextMenuRoute<const Kind extends ContextMenuKind>(kind: Kind, ...names: NamesFor<Kind>[]) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertContextMenuRoute<Kind, TCtor>): void {\n storeInteractionRoute(contextMenuRouteOf(kind), names, constructor);\n };\n}\n\n/**\n * Routes button interactions to handler classes.\n *\n * Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's\n * generic. Passing different definitions to the decorator and the generic is a compile error. Routing\n * matches the stable prefix, so a wire minted from an older shape still reaches the handler, where\n * reading this.params throws StaleCustomId and the controller boundary turns it into a reply.\n *\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n */\nexport function ButtonRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertComponentRoute<'button', Defs, TCtor>): void {\n storeComponentRoute(InteractionRoutes.Button, defs, constructor);\n };\n}\n\n/**\n * Routes modal submissions to handler classes.\n *\n * Pass the {@link CustomId} definition(s) this handler decodes and list the same ones in the handler's\n * generic. Passing different definitions to the decorator and the generic is a compile error. Routing\n * matches the stable prefix here too, throwing StaleCustomId on read the same as a button route.\n *\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n */\nexport function ModalRoute<const Defs extends readonly AnyCustomId[]>(...defs: Defs) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertComponentRoute<'modal', Defs, TCtor>): void {\n storeComponentRoute(InteractionRoutes.Modal, defs, constructor);\n };\n}\n\n/**\n * Routes select menu interactions to handler classes.\n *\n * Pass the select kind and the {@link CustomId} definition(s) this handler decodes. The handler's\n * generic must list the same kind and definitions, or it is a compile error.\n *\n * @param type - Select menu kind from {@link SelectMenuKind}.\n * @param defs - The customId definition(s) this handler decodes, one per route.\n * @decorator\n *\n * @example\n * ```typescript\n * \\@SelectMenuRoute(SelectMenuKind.User, AssignId)\n * class AssignSelect extends SelectMenuHandler<SelectMenuKind.User, [typeof AssignId]> {}\n * ```\n */\nexport function SelectMenuRoute<const Kind extends SelectMenuKind, const Defs extends readonly AnyCustomId[]>(\n type: Kind,\n ...defs: Defs\n) {\n return function <TCtor extends AnyHandlerCtor>(constructor: AssertComponentRoute<Kind, Defs, TCtor>): void {\n storeComponentRoute(selectMenuRouteOf(type), defs, constructor);\n };\n}\n","/**\n * The per-dispatch bag. Any code can merge fields into it by declaration merging, the\n * same pattern as {@link SlashOptionRegistry}. It stays empty until one does, so `keyof DispatchState` is\n * `never` and the bag is inert.\n */\nexport interface DispatchState {}\n\n/**\n * A typed bag allocated once per interaction dispatch and handed to the handler. The middleware and i18n\n * work reads and writes it through {@link DispatchState}. Today the bag is empty, so it only carries the\n * dispatched `routeId`.\n */\nexport class DispatchContext {\n private readonly state: Partial<DispatchState> = {};\n\n constructor(public readonly routeId: string | null) {}\n\n set<Key extends keyof DispatchState>(key: Key, value: DispatchState[Key]): void {\n this.state[key] = value;\n }\n\n get<Key extends keyof DispatchState>(key: Key): DispatchState[Key] | undefined {\n return this.state[key];\n }\n}\n","import { Logger } from '@seedcord/logger';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { DispatchContext } from '#src/dispatch/DispatchContext';\nimport type { LoggerChannelId } from '@seedcord/types';\n\n/**\n * Base class every transport handler extends. Don't register handlers directly. Use the more specific\n * handler subclasses.\n *\n * @typeParam Event - The event or interaction this handler processes\n * @typeParam TCore - The transport's Core\n */\nexport abstract class BaseHandler<Event, TCore extends CoreBase> {\n protected readonly event: Event;\n protected readonly logger: Logger;\n // absent on event handlers\n protected readonly dispatch?: DispatchContext | undefined;\n\n protected constructor(\n event: Event,\n public readonly core: TCore,\n dispatch?: DispatchContext,\n channel?: LoggerChannelId\n ) {\n this.event = event;\n this.logger = new Logger(this.constructor.name, { channel });\n this.dispatch = dispatch;\n }\n\n /**\n * Holds the main logic of your handler. The dispatcher calls it after the handler's gates pass, so a\n * gate that refuses stops `execute()` from running.\n */\n abstract execute(): Promise<void>;\n}\n","import { BaseHandler } from './BaseHandler';\n\nimport type { CoreBase } from '#interfaces/CoreBase';\nimport type { BaseReplySender } from '#reply/BaseReplySender';\nimport type { DispatchContext } from '#src/dispatch/DispatchContext';\nimport type { DeferOpts, ReplyResponse, SendOpts } from '@seedcord/types';\n\n/**\n * Shared base the repliable handlers on both transports extend. Defines the reply members over the sender\n * the transport builds.\n *\n * @typeParam Event - The repliable interaction type this handler processes\n * @typeParam TCore - The transport's Core\n * @typeParam TMessage - The transport's created-message lens\n * @typeParam TNative - The transport's own file forms, beyond the portable `ReplyFile`\n * @typeParam TSender - The transport's reply sender\n */\nexport abstract class RepliableHandler<\n Event,\n TCore extends CoreBase,\n TMessage extends { id: string },\n TNative,\n TSender extends BaseReplySender<TMessage, TNative>\n> extends BaseHandler<Event, TCore> {\n protected readonly sender: TSender;\n protected readonly routeId: string;\n\n protected constructor(event: Event, core: TCore, dispatch?: DispatchContext) {\n super(event, core, dispatch, 'interactions');\n this.routeId = dispatch?.routeId ?? this.constructor.name;\n // the override runs before its own field initializers\n this.sender = this.buildSender(event, core, this.routeId);\n }\n\n protected abstract buildSender(event: Event, core: TCore, routeId: string): TSender;\n\n /** @internal The dispatcher's fault boundary replies through the live ack state. */\n public getSender(): TSender {\n return this.sender;\n }\n\n /** Send the initial response, exactly once. */\n protected reply(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.reply(response, opts);\n }\n\n /** Show a \"thinking\" placeholder, then fill it later with {@link edit}. */\n protected defer(opts?: DeferOpts): Promise<void> {\n return this.sender.defer(opts);\n }\n\n /** Send a new message once the interaction is acknowledged. */\n protected followUp(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.followUp(response, opts);\n }\n\n /** Rewrite the initial reply or deferred placeholder. The targeted form rewrites a message a prior send returned. */\n protected edit(response: ReplyResponse<TNative> | string): Promise<TMessage>;\n protected edit(target: TMessage, response: ReplyResponse<TNative> | string): Promise<TMessage>;\n protected edit(\n targetOrResponse: TMessage | ReplyResponse<TNative> | string,\n maybeResponse?: ReplyResponse<TNative> | string\n ): Promise<TMessage> {\n // justified: the overloads narrow targetOrResponse to a response once maybeResponse is absent\n if (maybeResponse === undefined) return this.sender.edit(targetOrResponse as ReplyResponse<TNative> | string);\n // justified: the overloads narrow targetOrResponse to a target message once maybeResponse is defined\n return this.sender.edit(targetOrResponse as TMessage, maybeResponse);\n }\n\n /** Routes to reply, followUp, or edit based on the current ack state. */\n protected send(response: ReplyResponse<TNative> | string, opts?: SendOpts): Promise<TMessage> {\n return this.sender.send(response, opts);\n }\n\n /** Delete the initial reply or deferred placeholder. Pass a target to delete a message a prior send returned. */\n protected delete(target?: TMessage): Promise<void> {\n return target === undefined ? this.sender.delete() : this.sender.delete(target);\n }\n}\n","import { Notice } from './Notice';\nimport { NoticeCard } from './NoticeCard';\n\nimport type { RenderContext, ReplyResponse } from '@seedcord/types';\n\n/**\n * A generic fault you throw after catching an error you do not have a specific message for.\n *\n * The user sees a fixed generic reply with the tracking uuid, never the cause. `report` defaults to\n * `true`, so the framework logs it and publishes it to the `handledException` bus. Pass `report: false`\n * to show the generic reply without the bus publish. The original error is stored as the standard\n * `cause`, so the real stack reaches the webhook. When the user should see a real message for a fault,\n * subclass {@link Notice} and write your own `render` instead.\n *\n * The framework also renders this for an unhandled throw, where it points the user at\n * `ctx.developerUsername`.\n *\n * @example\n * ```ts\n * import { Fault } from '@seedcord/gateway';\n *\n * try {\n * await db.write(record);\n * } catch (cause) {\n * // user sees the generic reply with the uuid, and the real error rides along as cause for the webhook\n * throw new Fault({ cause });\n *\n * // pass report: false to show the same reply without publishing to the handledException bus\n * // throw new Fault({ cause, report: false });\n * }\n * ```\n */\nexport class Fault extends Notice {\n public constructor(options?: { cause?: unknown; report?: boolean }) {\n super('A fault occurred', options?.cause === undefined ? undefined : { cause: options.cause });\n this.report = options?.report ?? true;\n }\n\n public render(ctx: RenderContext): ReplyResponse {\n const contact = ctx.developerUsername ?? 'the developer';\n const card = new NoticeCard(\n `Something went wrong. Please reach out to ${contact} with a way to reproduce the error and the following:\\n### UUID: \\`${ctx.uuid}\\``,\n 'Error'\n );\n return { components: [card.component] };\n }\n}\n","import { NeedsAny, NotAllowed } from '#notices/index';\nimport { Fault } from '#stops/Fault';\nimport { Notice } from '#stops/Notice';\n\nimport { markCommits, rollbackCommits, runCheck } from './effects';\nimport { defineGate } from './Gate';\n\nimport type { Gate, GateContextBase, RequiredOf } from './Gate';\nimport type { IntersectRequired, JoinNames, TwoOrMore } from './matching';\n\n/**\n * Runs each gate in order and refuses on the first refusal. Takes two or more arms. The required\n * context is the intersection of the arms, so an event-only and an interaction-only gate cannot be\n * combined.\n *\n * @typeParam Gates - The tuple of two or more gate arms, run left to right.\n * @param gates - The gate arms to run in order, all refused on the first refusal.\n *\n * @see {@link or}\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n *\n * \\@Gated(and(GuildOnly(), RequirePermissions([PermissionFlagsBits.BanMembers])))\n * \\@SlashRoute('ban')\n * class BanHandler extends SlashHandler<'ban'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function and<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...gates: Gates\n): Gate<IntersectRequired<Gates> & GateContextBase, JoinNames<Gates, ' & '>>;\nexport function and(...gates: readonly Gate<GateContextBase>[]): Gate<GateContextBase> {\n return defineGate(gates.map((gate) => gate.name).join(' & '), async (ctx) => {\n for (const gate of gates) {\n await runCheck(gate, ctx);\n }\n });\n}\n\n// the caller-supplied refusal when every or arm refuses, replacing the default list or neutral refusal\ninterface OrOptions {\n fail: Notice | ((ctx: GateContextBase) => Notice);\n}\n\n// a gate has a check method, but the options object does not\nfunction isOrOptions(arg: Gate<GateContextBase> | OrOptions): arg is OrOptions {\n return !('check' in arg);\n}\n\n/**\n * Runs each gate in order and passes on the first arm that passes. Takes two or more arms. The\n * required context is the union of the arms. A handler that matches any one arm fits. When every\n * arm refuses it throws the trailing {@link OrOptions} `fail` if given, else an auto list of the\n * arms derived from the summary field, else a default refusal. The trailing options object does not\n * count as an arm.\n *\n * @typeParam Gates - The tuple of two or more gate arms, tried left to right.\n * @param gates - The gate arms to try in order, with an optional trailing {@link OrOptions} object.\n *\n * @see {@link and}\n *\n * @example\n * ```ts\n * \\@Gated(or(OwnerOnly(), RequireRole('123456789012345678')))\n * \\@SlashRoute('admin')\n * class AdminHandler extends SlashHandler<'admin'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function or<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...gates: Gates\n): Gate<RequiredOf<Gates[number]>, JoinNames<Gates, ' | '>>;\n/**\n * @example\n * ```ts\n * // custom refusal when every arm refuses\n * or(OwnerOnly(), RequireRole('123456789012345678'), { fail: new NotAllowedNotice() });\n * ```\n */\nexport function or<Gates extends TwoOrMore<Gate<GateContextBase>>>(\n ...args: [...Gates, OrOptions]\n): Gate<RequiredOf<Gates[number]>, JoinNames<Gates, ' | '>>;\nexport function or(...args: readonly (Gate<GateContextBase> | OrOptions)[]): Gate<GateContextBase> {\n const last = args.at(-1);\n const options = last !== undefined && isOrOptions(last) ? last : undefined;\n const gates = (options ? args.slice(0, -1) : args) as readonly Gate<GateContextBase>[];\n\n return defineGate(gates.map((gate) => gate.name).join(' | '), async (ctx) => {\n const summaries: string[] = [];\n let everyArmHasSummary = true;\n for (const gate of gates) {\n const mark = markCommits(ctx);\n try {\n await runCheck(gate, ctx);\n return;\n } catch (error) {\n // only a refusal counts as an arm declining. a Fault (even report-false), a Silence, or a raw error stops everything\n if (error instanceof Notice && !(error instanceof Fault) && !error.report) {\n // the arm may have queued an effect's commit before refusing, so drop it before the winner carries it\n rollbackCommits(ctx, mark);\n if (error.summary === undefined) everyArmHasSummary = false;\n else summaries.push(error.summary);\n continue;\n }\n throw error;\n }\n }\n if (options) throw typeof options.fail === 'function' ? options.fail(ctx) : options.fail;\n // the auto-list shows only when every refusal gave a summary, because a partial list would mislead by omission\n if (everyArmHasSummary && summaries.length > 0) throw new NeedsAny(summaries);\n throw new NotAllowed();\n });\n}\n","import { defineGate } from '#gates/Gate';\nimport { NotInDm, NotInGuild, NotOwner } from '#notices/index';\n\nimport { pickNotice } from './options';\n\nimport type { Gate, GateContextBase } from '#gates/Gate';\nimport type { GateNoticeOptions } from './options';\n\n/**\n * Passes only for a user id listed in `config.ownerIds`, else refuses.\n *\n * Agnostic, so it attaches to interaction and event handlers alike. With no `ownerIds` configured it refuses every caller. Pass {@link GateNoticeOptions} to reword or replace the refusal.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from your transport package\n *\n * @example\n * ```ts\n * \\@Gated(OwnerOnly())\n * \\@SlashRoute('shutdown')\n * class ShutdownHandler extends SlashHandler<'shutdown'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // reword the refusal, keeping the embed styling\n * OwnerOnly({ message: 'Owners only.' });\n * ```\n */\nexport function OwnerOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'OwnerOnly'> {\n return defineGate('OwnerOnly', (ctx) => {\n const owners = ctx.core.config.ownerIds ?? [];\n if (ctx.userId !== null && owners.includes(ctx.userId)) return;\n throw pickNotice(options, (message) => new NotOwner(message));\n });\n}\n\n/**\n * Passes inside a guild, else refuses.\n *\n * Agnostic. Attaches to any handler kind. Often paired with `RequirePermissions` in an {@link and}.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from your transport package\n *\n * @example\n * ```ts\n * import { PermissionFlagsBits } from 'discord.js';\n *\n * \\@Gated(GuildOnly(), RequirePermissions([PermissionFlagsBits.Administrator]))\n * \\@SlashRoute('maintenance')\n * class Maintenance extends SlashHandler<'maintenance'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function GuildOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'GuildOnly'> {\n return defineGate('GuildOnly', (ctx) => {\n if (ctx.guildId) return;\n throw pickNotice(options, (message) => new NotInGuild(message));\n });\n}\n\n/**\n * Passes in a direct message, else refuses.\n *\n * Agnostic, fitting any handler kind. The inverse of {@link GuildOnly}, so combining the two in an {@link and} can never pass.\n *\n * @param options - Reword the default refusal with `message`, or replace it with `notice`.\n *\n * @see the `@Gated` decorator from your transport package\n *\n * @example\n * ```ts\n * \\@Gated(DmOnly())\n * \\@SlashRoute('verify')\n * class VerifyHandler extends SlashHandler<'verify'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function DmOnly(options?: GateNoticeOptions): Gate<GateContextBase, 'DmOnly'> {\n return defineGate('DmOnly', (ctx) => {\n if (!ctx.guildId) return;\n throw pickNotice(options, (message) => new NotInDm(message));\n });\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordTypeError } from '@seedcord/errors/internal';\nimport { parseDuration, type ValidDuration } from '@seedcord/utils';\n\nimport { defineEffectGate } from '#gates/Gate';\nimport { OnCooldown } from '#notices/index';\n\nimport type { EffectGate, GateContextBase } from '#gates/Gate';\nimport type { Notice } from '#stops/Notice';\nimport type { EpochMs } from '@seedcord/types';\n\n/**\n * Options for {@link Cooldown}. `per` sets the bucket the window applies to and `limit` the uses allowed per\n * window. `message` rewords the refusal and `notice` replaces it, both receiving the epoch ms the key frees\n * up so the refusal can show the retry time.\n *\n * @example\n * ```ts\n * // one use per channel, rewording the refusal with the retry time\n * Cooldown('10s', {\n * per: 'channel',\n * message: (resetAt) => `Slow down. Try again <t:${Math.round(resetAt / 1000)}:R>.`\n * });\n * ```\n *\n * @example\n * ```ts\n * // five uses per minute, per user\n * Cooldown('1m', { limit: 5 });\n * ```\n */\nexport interface CooldownOptions {\n /**\n * The bucket the cooldown window applies to. 'user' scopes by user ID (falls back to global when the source carries no user id). 'guild' scopes by guild ID (falls back to global if no guild), and 'channel' scopes by channel ID (falls back to global if no channel).\n *\n * @defaultValue `'user'`\n */\n per?: 'user' | 'guild' | 'channel';\n /**\n * Uses allowed inside one window before the gate refuses.\n *\n * @defaultValue `1`\n */\n limit?: number;\n /**\n * Reword the refusal, keeping the standard notice card. Receives the epoch ms the key frees up, to\n * show the retry time with `<t:${Math.round(resetAt / 1000)}:R>`.\n */\n message?: (resetAt: EpochMs) => string;\n /**\n * Replace the refusal Notice entirely, for full control or a translated copy. Receives the epoch ms the\n * key frees up.\n */\n notice?: (resetAt: EpochMs) => Notice;\n}\n\n// off-route ctxs have no route to key on. each Cooldown() call gets its own id to keep unrelated event handlers isolated\nlet anonSeq = 0;\n\nfunction scopeValue(ctx: GateContextBase, per: 'user' | 'guild' | 'channel'): string {\n if (per === 'guild') return ctx.guildId ?? 'global';\n if (per === 'channel') return ctx.channelId ?? 'global';\n return ctx.userId ?? 'global';\n}\n\n/**\n * Allows `limit` uses per window, scoped by `per`. A number `duration` is **seconds**, and a string is\n * a duration like `30m` or `24h`. An unparseable string throws a **SeedcordTypeError** at construction. The\n * slot is charged in commit, only after the whole gate set passes, so a later refusal never burns the cooldown.\n * That split also means two requests racing the same key can both pass before either charges the slot.\n * The key combines the handler's route with the window settings, keeping two different handlers on separate\n * windows. Reword the refusal with {@link CooldownOptions.message} or replace it with {@link CooldownOptions.notice}.\n *\n * @param duration - A number is seconds, and a string is a duration like `30m` or `24h`. An unparseable string throws a **SeedcordTypeError**.\n * @param options - Sets the scope with `per`, the uses per window with `limit`, and the refusal text with `message` or `notice`.\n *\n * @see the `@Gated` decorator from your transport package\n * @see {@link IRateLimiter}\n *\n * @example\n * ```ts\n * // a number argument is SECONDS\n * \\@Gated(Cooldown(5))\n * \\@SlashRoute('daily')\n * class DailyHandler extends SlashHandler<'daily'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n *\n * @example\n * ```ts\n * // a string is a duration, here scoped per guild (the default is per user)\n * Cooldown('30m', { per: 'guild' });\n * ```\n *\n * @example\n * ```ts\n * // a burst, 3 uses per 10 minutes per user, then it refuses until a slot frees\n * \\@Gated(Cooldown('10m', { limit: 3 }))\n * \\@SlashRoute('report')\n * class ReportHandler extends SlashHandler<'report'> {\n * async execute() {\n * // ...\n * }\n * }\n * ```\n */\nexport function Cooldown(\n duration: number | ValidDuration,\n options?: CooldownOptions\n): EffectGate<GateContextBase, 'Cooldown'> {\n let windowMs: number;\n if (typeof duration === 'number') {\n windowMs = duration * 1000;\n } else {\n const parsed = parseDuration(duration);\n if (parsed === null) throw new SeedcordTypeError(SeedcordErrorCode.GateInvalidCooldownDuration, [duration]);\n windowMs = parsed;\n }\n // refused the same way as an unparseable string, because a zero or negative window would never limit\n if (windowMs <= 0) {\n throw new SeedcordTypeError(SeedcordErrorCode.GateInvalidCooldownDuration, [String(duration)]);\n }\n\n const per = options?.per ?? 'user';\n // exactOptionalPropertyTypes rejects an explicit undefined key\n const window = options?.limit === undefined ? { windowMs } : { windowMs, limit: options.limit };\n const anonId = anonSeq++;\n // routed keys stay stable across restarts, letting a durable store rebuild the same window\n const keyOf = (ctx: GateContextBase): string =>\n `cooldown:${ctx.routeId ?? `anon${anonId}`}:${per}:w${windowMs}:l${options?.limit ?? 1}:${scopeValue(ctx, per)}`;\n\n return defineEffectGate(\n 'Cooldown',\n async (ctx) => {\n const result = await ctx.core.rateLimiter.peek(keyOf(ctx), window);\n if (!result.limited) return;\n if (options?.notice) throw options.notice(result.resetAt);\n throw new OnCooldown(result.resetAt, options?.message?.(result.resetAt));\n },\n async (ctx) => {\n await ctx.core.rateLimiter.charge(keyOf(ctx), window);\n }\n );\n}\n","import { HasDangerousPermissions, MissingPermissions } from '#notices/index';\n\nimport { hasAll, missingNames, presentNames } from './bits';\n\nimport type { Notice } from '#stops/Notice';\nimport type { PermissionScope } from './bits';\n\n/** Replacement notices for the two refusals {@link assertPermissions} raises. */\nexport interface PermissionNoticeOverrides {\n missingNotice?: new (message: string | undefined, subject: string, missingPerms: readonly string[]) => Notice;\n dangerousNotice?: new (message: string | undefined, subject: string, dangerousPerms: readonly string[]) => Notice;\n}\n\n/** The check {@link assertPermissions} runs. */\nexport interface PermissionAssertion extends PermissionNoticeOverrides {\n /** Mention string for who is checked, used as the refusal's subject. */\n subject: string;\n /** The effective permission bitfield the subject holds, computed by the caller. */\n permissions: bigint;\n /** The permission flag bits to check. */\n scope: PermissionScope;\n /** Refuse when the subject holds a scope bit. */\n inverse?: boolean;\n}\n\n/**\n * Refuses when the subject is missing a permission in `scope`, or with `inverse` when it holds one.\n * The Administrator bit passes any scope, and on the inverse arm it reports every bit in `scope`.\n *\n * The caller computes `permissions`, gateway off a discord.js role, member, or channel, and HTTP off the\n * bitfield the interaction payload carries.\n *\n * @throws A {@link Notice} listing the missing or present permissions.\n *\n * @example\n * ```ts\n * import { assertPermissions } from '@seedcord/core';\n * import { PermissionFlagsBits } from 'discord-api-types/v10';\n *\n * // gateway, the bits come off a discord.js member\n * assertPermissions({\n * subject: `<@${member.id}>`,\n * permissions: member.permissions.bitfield,\n * scope: [PermissionFlagsBits.BanMembers]\n * });\n * ```\n *\n * @example\n * ```ts\n * // HTTP, the payload carries the member's bits as a string\n * assertPermissions({\n * subject: `<@${this.event.member.user.id}>`,\n * permissions: BigInt(this.event.member.permissions),\n * scope: [PermissionFlagsBits.ManageMessages]\n * });\n * ```\n *\n * @example\n * ```ts\n * // inverse, refuse a role that carries Administrator\n * assertPermissions({\n * subject: `<@&${role.id}>`,\n * permissions: role.permissions.bitfield,\n * scope: [PermissionFlagsBits.Administrator],\n * inverse: true\n * });\n * ```\n *\n * @example\n * ```ts\n * import { Notice } from '@seedcord/core';\n *\n * // a replacement notice takes the same three arguments the default one does\n * class CannotBan extends Notice {\n * public constructor(\n * message: string | undefined,\n * private readonly subject: string,\n * private readonly missing: readonly string[]\n * ) {\n * super(message ?? 'You cannot ban here.');\n * }\n *\n * public render(): ReplyResponse {\n * return { components: [new BanDenied(this.subject, this.missing).component] };\n * }\n * }\n *\n * assertPermissions({\n * subject: `<@${member.id}>`,\n * permissions: member.permissions.bitfield,\n * scope: [PermissionFlagsBits.BanMembers],\n * missingNotice: CannotBan\n * });\n * ```\n */\nexport function assertPermissions(check: PermissionAssertion): void {\n const { subject, permissions, scope, inverse = false, missingNotice, dangerousNotice } = check;\n\n if (inverse) {\n const present = presentNames(permissions, scope);\n if (present.length === 0) return;\n const Dangerous = dangerousNotice ?? HasDangerousPermissions;\n throw new Dangerous(undefined, subject, present);\n }\n\n if (hasAll(permissions, scope)) return;\n const Missing = missingNotice ?? MissingPermissions;\n throw new Missing(undefined, subject, missingNames(permissions, scope));\n}\n","/**\n * The role ids a member holds after adding and removing the given sets. Removals win over additions.\n *\n * This does not write the roles. Apply the result with `member.roles.set()` on gateway, or PATCH the member over HTTP.\n *\n * @param current - The role ids the member holds.\n * @param add - The role ids to add.\n * @param remove - The role ids to remove.\n * @returns The merged role ids.\n *\n * @example\n * ```ts\n * import { mergeRoles } from '@seedcord/core';\n *\n * // gateway\n * const ids = mergeRoles(member.roles.cache.map((role) => role.id), ['123'], ['456']);\n * await member.roles.set(ids);\n * ```\n */\nexport function mergeRoles(current: readonly string[], add: readonly string[], remove: readonly string[]): string[] {\n return [...new Set(current).union(new Set(add)).difference(new Set(remove))];\n}\n","import type { APIMessageComponentEmoji } from 'discord-api-types/v10';\n\n/**\n * A resolved custom emoji. Renders as `<:name:id>` in message content, or `<a:name:id>` when animated,\n * and passes straight to a builder's `setEmoji`.\n */\n// setEmoji in @discordjs/builders rejects any own key past these three, scanning with Object.entries\nexport class ResolvedEmoji implements APIMessageComponentEmoji {\n constructor(\n public readonly name: string,\n public readonly id: string,\n public readonly animated = false\n ) {}\n\n public toString(): string {\n return `<${this.animated ? 'a' : ''}:${this.name}:${this.id}>`;\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport type { PageView } from './PageView';\n\n/**\n * Pure page math, usable headless. Clamps `page` into range and slices the window.\n *\n * @param items - The full list to page over.\n * @param page - The requested zero-based page, clamped into `[0, totalPages - 1]`.\n * @param perPage - The page size. Must be a positive integer.\n * @returns The sliced {@link PageView}, with `totalPages` always known.\n * @throws SeedcordRangeError when `perPage` is not a positive integer.\n */\nexport function paginate<Item>(items: readonly Item[], page: number, perPage: number): PageView<Item> {\n if (!Number.isSafeInteger(perPage) || perPage <= 0) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationInvalidPerPage, [perPage]);\n }\n\n const totalPages = Math.max(1, Math.ceil(items.length / perPage));\n const clamped = Math.min(Math.max(Math.trunc(page), 0), totalPages - 1);\n const start = clamped * perPage;\n\n return {\n items: items.slice(start, start + perPage),\n page: clamped,\n perPage,\n totalPages,\n hasPrev: clamped > 0,\n hasNext: clamped < totalPages - 1\n };\n}\n","import { ActionRowBuilder, ButtonBuilder } from '@discordjs/builders';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError, SeedcordTypeError } from '@seedcord/errors/internal';\nimport { ButtonStyle } from 'discord-api-types/v10';\n\nimport { PAGE_MAX } from '#pagination/cursor';\n\nimport type { PageCursor } from '#pagination/cursor';\nimport type { PageView } from '#pagination/PageView';\nimport type { APIMessageComponentEmoji } from 'discord-api-types/v10';\n\n/** The five built-in nav controls. */\nexport type ControlKey = 'first' | 'prev' | 'indicator' | 'next' | 'last';\n\n// Link and Premium have no custom_id, which un-routes a control.\ntype CustomIdStyle = ButtonStyle.Primary | ButtonStyle.Secondary | ButtonStyle.Success | ButtonStyle.Danger;\n\n/** Cosmetic overrides for a control button. `style` excludes Link and Premium, which would un-route it. */\nexport interface ControlCosmetics {\n label?: string;\n style?: CustomIdStyle;\n emoji?: APIMessageComponentEmoji;\n}\n\n/** The controls passed to `render`. */\nexport interface PaginatorControls {\n /**\n * A fresh `ButtonBuilder` for one control, already stamped with its target page and disabled-at-bounds\n * state. Call only cosmetic setters on it, because a `setCustomId` or `setStyle(Link)` un-routes it.\n */\n button(key: ControlKey, cosmetics?: ControlCosmetics): ButtonBuilder;\n /**\n * Assemble an action row of the chosen controls, in order. Throws on an empty set, more than five\n * controls, or a duplicate.\n */\n row(...keys: ControlKey[]): ActionRowBuilder<ButtonBuilder>;\n}\n\nconst DEFAULT_LABEL: Record<ControlKey, string> = {\n first: 'First',\n prev: 'Prev',\n indicator: '',\n next: 'Next',\n last: 'Last'\n};\n\n// a distinct slot keeps two controls on the same page off the same id. 0-4 is the cursor's SLOT_MAX.\nconst CONTROL_SLOT: Record<ControlKey, number> = {\n first: 0,\n prev: 1,\n indicator: 2,\n next: 3,\n last: 4\n};\n\nconst MAX_BUTTONS_PER_ROW = 5;\n\nexport class Controls implements PaginatorControls {\n constructor(\n private readonly cursor: PageCursor<string>,\n private readonly view: PageView<unknown>\n ) {}\n\n button(key: ControlKey, cosmetics?: ControlCosmetics): ButtonBuilder {\n const { target, disabled } = this.navState(key);\n\n // an emoji with no explicit label makes an icon-only button. the indicator always shows its page text.\n const defaultLabel = key === 'indicator' ? this.indicatorText() : DEFAULT_LABEL[key];\n const label = cosmetics?.label ?? (key === 'indicator' || !cosmetics?.emoji ? defaultLabel : undefined);\n\n const button = new ButtonBuilder()\n // an enormous list could push last/next past PAGE_MAX, where encode throws.\n .setCustomId(this.cursor.encode({ page: Math.min(Math.max(0, target), PAGE_MAX), slot: CONTROL_SLOT[key] }))\n .setStyle(cosmetics?.style ?? ButtonStyle.Secondary)\n .setDisabled(disabled);\n if (label !== undefined) button.setLabel(label);\n if (cosmetics?.emoji) button.setEmoji(cosmetics.emoji);\n return button;\n }\n\n private navState(key: ControlKey): { target: number; disabled: boolean } {\n const { page, totalPages, hasPrev, hasNext } = this.view;\n const knownTotal = totalPages !== undefined;\n const target = {\n first: 0,\n prev: page - 1,\n indicator: page,\n next: page + 1,\n last: knownTotal ? totalPages - 1 : page\n }[key];\n // past PAGE_MAX the encoded page would clamp to a wrong one\n const disabled = {\n first: !hasPrev,\n prev: !hasPrev,\n indicator: true,\n next: !hasNext || page + 1 > PAGE_MAX,\n last: !hasNext || !knownTotal || totalPages - 1 > PAGE_MAX\n }[key];\n return { target, disabled };\n }\n\n row(...keys: ControlKey[]): ActionRowBuilder<ButtonBuilder> {\n if (keys.length === 0) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationEmptyControls);\n }\n if (keys.length > MAX_BUTTONS_PER_ROW) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationTooManyControls, [keys.length]);\n }\n // repeating a control reuses its slot and page, so the custom_ids collide and Discord rejects the message.\n const seen = new Set<ControlKey>();\n for (const key of keys) {\n if (seen.has(key)) throw new SeedcordTypeError(SeedcordErrorCode.PaginationDuplicateControls, [key]);\n seen.add(key);\n }\n return new ActionRowBuilder<ButtonBuilder>().addComponents(keys.map((key) => this.button(key)));\n }\n\n private indicatorText(): string {\n const { page, totalPages } = this.view;\n return totalPages === undefined ? `Page ${page + 1}` : `Page ${page + 1} of ${totalPages}`;\n }\n}\n","import { TextDisplayBuilder } from '@discordjs/builders';\n\nimport { BuilderComponent } from '#components/Component';\nimport { Controls } from '#pagination/controls';\n\nimport type { ControlKey, PaginatorControls } from '#pagination/controls';\nimport type { PageCursor } from '#pagination/cursor';\nimport type { PageView } from '#pagination/PageView';\nimport type { ButtonBuilder, ActionRowBuilder } from '@discordjs/builders';\nimport type { ReplyResponse, V2Component } from '@seedcord/types';\n\n/** What `renderItem` returns for one item, a text line or a section. */\nexport type ItemRender<Item> = (item: Item, index: number) => string | BuilderComponent<'section'>;\n\ntype Renderable = string | V2Component[] | ReplyResponse;\n\n/** A full-page render override. */\nexport type PageRender<Item> = (view: PageView<Item>, controls: PaginatorControls) => Renderable;\n\n// subclassed because BuilderComponent.instance is protected\nclass PageContainer<Item> extends BuilderComponent<'container'> {\n constructor(view: PageView<Item>, renderItem: ItemRender<Item>, controlRow: ActionRowBuilder<ButtonBuilder>) {\n super('container');\n const base = view.page * view.perPage;\n let lines: string[] = [];\n const flush = (): void => {\n if (lines.length === 0) return;\n this.instance.addTextDisplayComponents(new TextDisplayBuilder().setContent(lines.join('\\n')));\n lines = [];\n };\n view.items.forEach((item, offset) => {\n const rendered = renderItem(item, base + offset);\n if (typeof rendered === 'string') {\n lines.push(rendered);\n return;\n }\n flush();\n this.instance.addSectionComponents(rendered.component);\n });\n flush();\n this.instance.addActionRowComponents(controlRow);\n }\n}\n\nfunction toReplyResponse(renderable: Renderable): ReplyResponse {\n if (typeof renderable === 'string') return { components: [new TextDisplayBuilder().setContent(renderable)] };\n if (Array.isArray(renderable)) return { components: renderable };\n return renderable;\n}\n\nconst ARRAY_KEYS: ControlKey[] = ['first', 'prev', 'indicator', 'next', 'last'];\nconst CURSOR_KEYS: ControlKey[] = ['prev', 'indicator', 'next'];\n\n// a render override builds the whole tree, or the default container lists the items and appends\n// the controls (all five for a known total, prev/indicator/next for a cursor source)\nexport function renderPage<Item>(\n view: PageView<Item>,\n cursor: PageCursor<string>,\n config: { renderItem?: ItemRender<Item>; render?: PageRender<Item> }\n): ReplyResponse {\n const controls = new Controls(cursor, view);\n if (config.render) return toReplyResponse(config.render(view, controls));\n\n const renderItem = config.renderItem ?? String;\n const row = controls.row(...(view.totalPages === undefined ? CURSOR_KEYS : ARRAY_KEYS));\n return { components: [new PageContainer(view, renderItem, row).component] };\n}\n","import { pageCursor } from '#pagination/cursor';\nimport { renderPage } from '#pagination/render';\n\nimport type { PageCursor } from '#pagination/cursor';\nimport type { ItemRender, PageRender } from '#pagination/render';\nimport type { PageSource } from '#pagination/sources';\nimport type { ReplyResponse } from '@seedcord/types';\n\n/**\n * The transport-agnostic paginator configuration. Each transport adds its own handler wiring on top.\n *\n * @typeParam Item - The item type, inferred from the source.\n * @typeParam Prefix - The route prefix, inferred from `prefix`.\n * @typeParam Ctx - The transport's page context.\n */\nexport interface PaginatorConfig<Item, Prefix extends string, Ctx> {\n /** The route prefix used to build the page cursor on the nav buttons. */\n prefix: Prefix;\n source: PageSource<Item, Ctx>;\n /** Render one item, `index` is its absolute position across pages. Ignored when `render` is set. */\n renderItem?: ItemRender<Item>;\n /** Take over the whole page tree. Receives the page data and the controls factory. */\n render?: PageRender<Item>;\n /**\n * Whether the first page is ephemeral.\n *\n * @defaultValue `false`\n */\n ephemeral?: boolean;\n}\n\n/**\n * Holds a paginator's cursor and renders one page. Each transport extends this to add the nav handler and\n * the method that sends the first page.\n *\n * @typeParam Item - The item type, inferred from the source.\n * @typeParam Prefix - The route prefix, inferred from `config.prefix`.\n * @typeParam Ctx - The transport's page context.\n */\nexport abstract class PaginatorBase<Item, Prefix extends string, Ctx> {\n /** The page cursor, pass it to your `@ButtonRoute`. */\n public readonly cursor: PageCursor<Prefix>;\n\n protected readonly config: PaginatorConfig<Item, Prefix, Ctx>;\n\n protected constructor(config: PaginatorConfig<Item, Prefix, Ctx>) {\n this.cursor = pageCursor(config.prefix);\n this.config = config;\n }\n\n /** Render a page as a {@link ReplyResponse}. To post it elsewhere, add `flags: MessageFlags.IsComponentsV2`. */\n async page(ctx: Ctx, n: number): Promise<ReplyResponse> {\n const view = await this.config.source.page(ctx, n);\n return renderPage(view, this.cursor, this.config);\n }\n}\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError } from '@seedcord/errors/internal';\n\nimport { paginate } from '#pagination/paginate';\n\nimport type { PageView } from '#pagination/PageView';\nimport type { Promisable } from 'type-fest';\n\nconst DEFAULT_PER_PAGE = 10;\n\n/**\n * The one method a paginator calls on a source, once per click. Implement it to supply a custom source.\n *\n * @typeParam Item - The item type the source pages over.\n * @typeParam Ctx - The transport's page context, handed to the loader.\n */\nexport interface PageSource<Item, Ctx> {\n page(ctx: Ctx, n: number): Promise<PageView<Item>>;\n}\n\nfunction perPageOf(opts?: { perPage?: number }): number {\n const perPage = opts?.perPage ?? DEFAULT_PER_PAGE;\n if (!Number.isSafeInteger(perPage) || perPage <= 0) {\n throw new SeedcordRangeError(SeedcordErrorCode.PaginationInvalidPerPage, [perPage]);\n }\n return perPage;\n}\n\n/**\n * A source for a bounded list you can load whole. It loads the full list on every click, then slices the\n * page via {@link paginate}, so the real total is known (a real last button, \"Page X of Y\"). Cache inside\n * your loader if the load is expensive.\n *\n * @typeParam Item - The item type, inferred from the loader's return.\n * @typeParam Ctx - The transport's page context. Each transport exports a subclass that fixes it.\n */\nexport class ArraySource<Item, Ctx> implements PageSource<Item, Ctx> {\n private readonly perPage: number;\n\n constructor(\n private readonly load: (ctx: Ctx) => Promisable<readonly Item[]>,\n opts?: { perPage?: number }\n ) {\n this.perPage = perPageOf(opts);\n }\n\n async page(ctx: Ctx, n: number): Promise<PageView<Item>> {\n return paginate(await this.load(ctx), n, this.perPage);\n }\n}\n\n/**\n * A source for a large or unknown-length set you fetch one page at a time (SQL LIMIT/OFFSET, a paged API).\n * The fetcher receives the page index and the page size and reports whether a next page exists. A cursor\n * source has no cheap total, so `totalPages` is undefined, the last button is omitted, and the indicator\n * reads \"Page X\".\n *\n * @typeParam Item - The item type, inferred from the fetcher's slice.\n * @typeParam Ctx - The transport's page context. Each transport exports a subclass that fixes it.\n */\nexport class CursorSource<Item, Ctx> implements PageSource<Item, Ctx> {\n private readonly perPage: number;\n\n constructor(\n private readonly fetch: (\n ctx: Ctx,\n page: number,\n perPage: number\n ) => Promisable<{ items: readonly Item[]; hasNext: boolean }>,\n opts?: { perPage?: number }\n ) {\n this.perPage = perPageOf(opts);\n }\n\n async page(ctx: Ctx, n: number): Promise<PageView<Item>> {\n const page = Math.max(0, Math.trunc(n));\n const { items, hasNext } = await this.fetch(ctx, page, this.perPage);\n return { items: [...items], page, perPage: this.perPage, hasPrev: page > 0, hasNext };\n }\n}\n","import 'reflect-metadata';\n\nexport type * from '#registries/ContextMenuRegistry';\nexport type * from '#registries/SlashOptionRegistry';\n\nexport { Commands, ContextMenus } from '#src/commands/CommandInjector';\nexport type {\n CommandInfo,\n ContextMenuInfo,\n InjectedCommandMap,\n InjectedContextMenuMap\n} from '#src/commands/CommandInjector';\n\nexport { RegisterCommand } from '#decorators/Command';\nexport { SelectMenuKind } from '#decorators/interactionRoutes';\nexport {\n AutocompleteRoute,\n ButtonRoute,\n ContextMenuRoute,\n ModalRoute,\n SelectMenuRoute,\n SlashRoute\n} from '#decorators/routes';\n\nexport { DispatchContext } from '#src/dispatch/DispatchContext';\nexport type { DispatchState } from '#src/dispatch/DispatchContext';\n\nexport { BaseHandler } from '#src/handlers/BaseHandler';\nexport { RepliableHandler } from '#src/handlers/RepliableHandler';\n\nexport type { CoreBase } from '#interfaces/CoreBase';\n\nexport type { Initializeable } from '#src/plugin/Plugin';\n\nexport { ShutdownPhase, StartupPhase } from '#src/lifecycle/phases';\n\nexport { defineEffectGate, defineGate } from '#gates/Gate';\nexport type { EffectGate, Gate, GateContextBase, GuildPermissionsContext, RequiredOf } from '#gates/Gate';\nexport { and, or } from '#gates/combinators';\nexport { DmOnly, GuildOnly, OwnerOnly } from '#gates/catalog/access';\nexport { Cooldown, type CooldownOptions } from '#gates/catalog/Cooldown';\nexport { RequireBotPermissions, RequirePermissions, RequireRole } from '#gates/catalog/permissions';\nexport type { PermissionScope, RequirePermissionsOptions, RequireRoleOptions } from '#gates/catalog/permissions';\nexport type { GateNoticeOptions } from '#gates/catalog/options';\n\nexport { assertPermissions } from '#src/permissions/assert';\nexport type { PermissionAssertion, PermissionNoticeOverrides } from '#src/permissions/assert';\nexport { mergeRoles } from '#src/permissions/mergeRoles';\n\nexport { BuilderComponent, RowComponent } from '#components/Component';\nexport { type RowType, type BuilderType } from '#components/builderTypes';\n\nexport { Notice } from '#stops/Notice';\nexport { Fault } from '#stops/Fault';\nexport { Silence } from '#stops/Silence';\n\nexport { CustomId } from '#customId/CustomId';\n\nexport { ResolvedEmoji } from '#src/miscellaneous/emoji';\n\nexport type { AutocompleteOptions } from '#inputs/AutocompleteOptions';\n\nexport { paginate } from '#pagination/paginate';\nexport { type PageView } from '#pagination/PageView';\nexport { PaginatorBase } from '#pagination/PaginatorBase';\nexport type { PaginatorConfig } from '#pagination/PaginatorBase';\nexport { ArraySource, CursorSource } from '#pagination/sources';\nexport type { PageSource } from '#pagination/sources';\nexport type { ControlCosmetics, ControlKey, PaginatorControls } from '#pagination/controls';\nexport type { ItemRender, PageRender } from '#pagination/render';\n\nexport { Bus, Subscribe, Subscriber, WebhookLog, WebhookUrl } from '#subscribers/index';\nexport type {\n DispatchOutcome,\n FaultSource,\n SubscribeOptions,\n Subscriptions,\n SubscriptionData,\n SubscriptionKey,\n WebhookFile,\n WebhookReport\n} from '#subscribers/index';\n\n/** Package version */\nexport const version = process.env.PACKAGE_VERSION ?? '0.0.0';\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { $ as Promisable, A as ModalLike, B as areRoutes, C as Gate, F as ComponentKindBrand, G as storeInteractionRoute, H as interactionRoutesOf, I as ContextMenuKindBrand, J as decodeFor, K as AnyCustomId, L as SlashRouteBrand, M as serializeReply, N as AutocompleteRouteBrand, P as ComponentDefsBrand, R as RoutableConstructor, U as selectMenuRouteOf, V as contextMenuRouteOf, W as storeComponentRoute, X as DecodedParams, Y as prefixOf, Z as CommandMeta, _ as pickNotice, c as FocusedField, et as IsNever, ft as OptionKind, i as AutocompletableNames, j as SerializedReply, k as BaseReplySender, m as PermissionNames, mt as SlashOptionRegistry, n as PageCursor, o as ChoiceValueOf, ot as CommandInjector, r as pageCursor, s as EntryFor, t as PAGE_MAX, tt as BuilderComponent, v as GateFitsWith, w as GateContextBase } from "./cursor-
|
|
1
|
+
import { $ as Promisable, A as ModalLike, B as areRoutes, C as Gate, F as ComponentKindBrand, G as storeInteractionRoute, H as interactionRoutesOf, I as ContextMenuKindBrand, J as decodeFor, K as AnyCustomId, L as SlashRouteBrand, M as serializeReply, N as AutocompleteRouteBrand, P as ComponentDefsBrand, R as RoutableConstructor, U as selectMenuRouteOf, V as contextMenuRouteOf, W as storeComponentRoute, X as DecodedParams, Y as prefixOf, Z as CommandMeta, _ as pickNotice, c as FocusedField, et as IsNever, ft as OptionKind, i as AutocompletableNames, j as SerializedReply, k as BaseReplySender, m as PermissionNames, mt as SlashOptionRegistry, n as PageCursor, o as ChoiceValueOf, ot as CommandInjector, r as pageCursor, s as EntryFor, t as PAGE_MAX, tt as BuilderComponent, v as GateFitsWith, w as GateContextBase } from "./cursor-0Dpi07Sj.mjs";
|
|
2
2
|
import { n as CommandBuilder, r as DeployResult } from "./basic-Dng__Ena.mjs";
|
|
3
|
-
import { A as reportedWrite, B as InteractionMetadataKey, C as DispatchOutcome, F as AckTrace, G as WebhookUrlMetadataKey, H as InteractionRoutes, I as PublishDefault, L as CommandMetadataKey, M as ReplyMethod, N as checkAckLegality, O as Notice, P as sendTarget, R as EventMetadataKey, S as DefaultSubscriptions, U as MiddlewareMetadataKey, V as InteractionRouteKeys, W as SubscribeMetadataKey, _ as Bus, a as PluginCtor, b as busLoggerOf, i as PluginArgs, j as AckState, k as ReplyTelemetry, v as StoredSubscriberCtor, y as SubscriberRegistration, z as GatedMetadataKey } from "./Plugin-
|
|
3
|
+
import { A as reportedWrite, B as InteractionMetadataKey, C as DispatchOutcome, F as AckTrace, G as WebhookUrlMetadataKey, H as InteractionRoutes, I as PublishDefault, L as CommandMetadataKey, M as ReplyMethod, N as checkAckLegality, O as Notice, P as sendTarget, R as EventMetadataKey, S as DefaultSubscriptions, U as MiddlewareMetadataKey, V as InteractionRouteKeys, W as SubscribeMetadataKey, _ as Bus, a as PluginCtor, b as busLoggerOf, i as PluginArgs, j as AckState, k as ReplyTelemetry, v as StoredSubscriberCtor, y as SubscriberRegistration, z as GatedMetadataKey } from "./Plugin-B6iRzm3g.mjs";
|
|
4
4
|
import { n as contextMenuLeaves, t as ContextMenuLeaves } from "./contextMenuLeaves-COzDYa6c.mjs";
|
|
5
5
|
import "reflect-metadata";
|
|
6
6
|
import { ContextMenuCommandBuilder, SlashCommandBuilder } from "@discordjs/builders";
|
package/dist/internal.index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { C as WebhookUrlMetadataKey, S as SubscribeMetadataKey, _ as GatedMetadataKey, b as InteractionRoutes, d as sendFlags, g as EventMetadataKey, h as CommandMetadataKey, i as PublishDefault, l as ReportThrottle, m as setBotColor, n as busLoggerOf, u as deferFlags, v as InteractionMetadataKey, w as contextMenuLeaves, x as MiddlewareMetadataKey, y as InteractionRouteKeys } from "./Bus-DcuUtOEL.mjs";
|
|
2
|
-
import { A as areRoutes, B as prefixOf, C as NotInDm, E as OnCooldown, F as storeInteractionRoute, H as Notice, I as ComponentDefsKey, J as guardedAccessor, K as accessorStore, L as decodeComponentRoute, M as interactionRoutesOf, N as selectMenuRouteOf, P as storeComponentRoute, S as NotAllowed, T as NotOwner, U as CommandInjector, V as NoticeCard, _ as GateNotice, b as MissingRole, d as pickNotice, f as discardCommits, g as runCommits, h as runCheck, j as contextMenuRouteOf, n as pageCursor, q as clearStore, r as Silence, s as PermissionNames, t as PAGE_MAX, v as HasDangerousPermissions, w as NotInGuild, x as NeedsAny, y as MissingPermissions, z as decodeFor } from "./cursor-
|
|
2
|
+
import { A as areRoutes, B as prefixOf, C as NotInDm, E as OnCooldown, F as storeInteractionRoute, H as Notice, I as ComponentDefsKey, J as guardedAccessor, K as accessorStore, L as decodeComponentRoute, M as interactionRoutesOf, N as selectMenuRouteOf, P as storeComponentRoute, S as NotAllowed, T as NotOwner, U as CommandInjector, V as NoticeCard, _ as GateNotice, b as MissingRole, d as pickNotice, f as discardCommits, g as runCommits, h as runCheck, j as contextMenuRouteOf, n as pageCursor, q as clearStore, r as Silence, s as PermissionNames, t as PAGE_MAX, v as HasDangerousPermissions, w as NotInGuild, x as NeedsAny, y as MissingPermissions, z as decodeFor } from "./cursor-BRyCNqRV.mjs";
|
|
3
3
|
import { n as setDevChannel, t as getDevChannel } from "./devChannel-CQU7hq7Q.mjs";
|
|
4
4
|
import { t as slashRouteLeaves } from "./slashRouteLeaves-De1SxqnX.mjs";
|
|
5
5
|
import "reflect-metadata";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as CommandBuilder, r as DeployResult } from "./basic-Dng__Ena.mjs";
|
|
2
|
-
import { _ as Bus, a as PluginCtor, d as Transport, f as TransportAssert, g as CoreBase, h as StartupPhase, i as PluginArgs, l as Runtime, m as ShutdownPhase, n as Initializeable, o as PluginLike, s as ChannelKeyAssert, t as CoreParamAssert, u as RuntimeAssert } from "./Plugin-
|
|
3
|
-
import "./index-
|
|
2
|
+
import { _ as Bus, a as PluginCtor, d as Transport, f as TransportAssert, g as CoreBase, h as StartupPhase, i as PluginArgs, l as Runtime, m as ShutdownPhase, n as Initializeable, o as PluginLike, s as ChannelKeyAssert, t as CoreParamAssert, u as RuntimeAssert } from "./Plugin-B6iRzm3g.mjs";
|
|
3
|
+
import "./index-uBwh8r7x.mjs";
|
|
4
4
|
import { t as ContextMenuLeaves } from "./contextMenuLeaves-COzDYa6c.mjs";
|
|
5
5
|
import { Logger } from "@seedcord/logger";
|
|
6
6
|
import { REST } from "@discordjs/rest";
|
package/dist/plugin.index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { c as PluginOptions, n as Initializeable, p as PluginLifecycleSpec, r as Plugin } from "./Plugin-
|
|
1
|
+
import { c as PluginOptions, n as Initializeable, p as PluginLifecycleSpec, r as Plugin } from "./Plugin-B6iRzm3g.mjs";
|
|
2
2
|
import { HmrAware, HmrUpdateEvent } from "@seedcord/types";
|
|
3
3
|
export { type HmrAware, type HmrUpdateEvent, type Initializeable, Plugin, type PluginLifecycleSpec, type PluginOptions };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seedcord/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.1-next.0",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=24.11"
|
|
7
7
|
},
|
|
@@ -71,19 +71,19 @@
|
|
|
71
71
|
"@discordjs/rest": "^2.6.3",
|
|
72
72
|
"discord-api-types": "^0.38.52",
|
|
73
73
|
"reflect-metadata": "^0.2.2",
|
|
74
|
-
"@seedcord/errors": "^0.4.
|
|
75
|
-
"@seedcord/event-emitter": "^0.1.
|
|
76
|
-
"@seedcord/logger": "^0.2.
|
|
77
|
-
"@seedcord/types": "^0.9.
|
|
78
|
-
"@seedcord/utils": "^0.8.
|
|
74
|
+
"@seedcord/errors": "^0.4.1-next.0",
|
|
75
|
+
"@seedcord/event-emitter": "^0.1.4-next.0",
|
|
76
|
+
"@seedcord/logger": "^0.2.1-next.0",
|
|
77
|
+
"@seedcord/types": "^0.9.1-next.0",
|
|
78
|
+
"@seedcord/utils": "^0.8.6-next.0"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"envapt": "^8.1.1",
|
|
82
82
|
"type-fest": "^5.8.0",
|
|
83
83
|
"vite": "^8.2.0",
|
|
84
|
-
"@seedcord/eslint-config": "^1.5.
|
|
85
|
-
"@seedcord/rate-limiter": "^0.1.
|
|
86
|
-
"@seedcord/tsconfig": "^2.0.3
|
|
84
|
+
"@seedcord/eslint-config": "^1.5.5-next.0",
|
|
85
|
+
"@seedcord/rate-limiter": "^0.1.4-next.0",
|
|
86
|
+
"@seedcord/tsconfig": "^2.0.3",
|
|
87
87
|
"@seedcord/tsdown-config": "^2.0.1",
|
|
88
88
|
"@seedcord/vitest-config": "^0.0.1"
|
|
89
89
|
},
|