@seedcord/core 0.1.0-next.1 → 0.1.0-next.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CustomId--QizzBOn.d.mts +660 -0
- package/dist/{CustomId-CqiuEllp.cjs → CustomId-DV7daU7r.cjs} +321 -87
- package/dist/CustomId-DV7daU7r.cjs.map +1 -0
- package/dist/{CustomId-XgZ2KDgT.mjs → CustomId-epJayEGO.mjs} +196 -88
- package/dist/CustomId-epJayEGO.mjs.map +1 -0
- package/dist/index.cjs +347 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +230 -48
- package/dist/index.mjs +339 -6
- package/dist/index.mjs.map +1 -1
- package/dist/internal.index.cjs +50 -1
- package/dist/internal.index.cjs.map +1 -1
- package/dist/internal.index.d.mts +61 -41
- package/dist/internal.index.mjs +32 -2
- package/dist/internal.index.mjs.map +1 -1
- package/package.json +8 -4
- package/dist/CustomId-BJF6mbJs.d.mts +0 -317
- package/dist/CustomId-CqiuEllp.cjs.map +0 -1
- package/dist/CustomId-XgZ2KDgT.mjs.map +0 -1
|
@@ -1,47 +1,67 @@
|
|
|
1
|
-
import { a as CustomIdField, i as prefixOf, n as CustomId, o as DecodedParams,
|
|
1
|
+
import { C as BuilderComponent, a as CustomIdField, c as pickNotice, g as GateContextBase, h as Gate, i as prefixOf, l as GateFitsWith, n as CustomId, o as DecodedParams, p as Notice, r as decodeFor, t as AnyCustomId, x as CommandMeta } from "./CustomId--QizzBOn.mjs";
|
|
2
|
+
import { BotColor, EpochMs, ReplyResponse } from "@seedcord/types";
|
|
2
3
|
|
|
3
|
-
//#region src/components/colors.d.ts
|
|
4
|
-
declare const Colors: {
|
|
5
|
-
readonly Aqua: 1752220;
|
|
6
|
-
readonly Blue: 3447003;
|
|
7
|
-
readonly Blurple: 5793266;
|
|
8
|
-
readonly DarkAqua: 1146986;
|
|
9
|
-
readonly DarkBlue: 2123412;
|
|
10
|
-
readonly DarkButNotBlack: 2895667;
|
|
11
|
-
readonly DarkerGrey: 8359053;
|
|
12
|
-
readonly DarkGold: 12745742;
|
|
13
|
-
readonly DarkGreen: 2067276;
|
|
14
|
-
readonly DarkGrey: 9936031;
|
|
15
|
-
readonly DarkNavy: 2899536;
|
|
16
|
-
readonly DarkOrange: 11027200;
|
|
17
|
-
readonly DarkPurple: 7419530;
|
|
18
|
-
readonly DarkRed: 10038562;
|
|
19
|
-
readonly DarkVividPink: 11342935;
|
|
20
|
-
readonly Default: 0;
|
|
21
|
-
readonly Fuchsia: 15418782;
|
|
22
|
-
readonly Gold: 15844367;
|
|
23
|
-
readonly Green: 5763719;
|
|
24
|
-
readonly Grey: 9807270;
|
|
25
|
-
readonly Greyple: 10070709;
|
|
26
|
-
readonly LightGrey: 12370112;
|
|
27
|
-
readonly LuminousVividPink: 15277667;
|
|
28
|
-
readonly Navy: 3426654;
|
|
29
|
-
readonly NotQuiteBlack: 2303786;
|
|
30
|
-
readonly Orange: 15105570;
|
|
31
|
-
readonly Purple: 10181046;
|
|
32
|
-
readonly Red: 15548997;
|
|
33
|
-
readonly White: 16777215;
|
|
34
|
-
readonly Yellow: 16705372;
|
|
35
|
-
};
|
|
36
|
-
/** A discord.js color name, or `'Random'`. */
|
|
37
|
-
type ColorName = keyof typeof Colors | 'Random';
|
|
38
|
-
/** Any color the bot color accepts: a name, a raw integer, a `#hex` string, or an rgb tuple. */
|
|
39
|
-
type BotColor = ColorName | number | `#${string}` | readonly [number, number, number];
|
|
40
|
-
//#endregion
|
|
41
4
|
//#region src/components/botColorHolder.d.ts
|
|
42
|
-
/** @internal */
|
|
43
5
|
declare function setBotColor(color: BotColor | undefined): void;
|
|
44
6
|
//#endregion
|
|
7
|
+
//#region src/gates/runGates.d.ts
|
|
8
|
+
declare function routeIdOf(handlerCtor: object): string | null;
|
|
9
|
+
/**
|
|
10
|
+
* Runs each gate's check in order, so the first refusal propagates to the dispatcher boundary. An effect
|
|
11
|
+
* gate's commit runs once the whole set passes.
|
|
12
|
+
*/
|
|
13
|
+
declare function runGates(gates: readonly Gate<GateContextBase>[], ctx: GateContextBase): Promise<void>;
|
|
14
|
+
declare function runHandlerGates(handlerCtor: object, ctx: GateContextBase): Promise<void>;
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/notices/index.d.ts
|
|
17
|
+
declare abstract class GateNotice extends Notice {
|
|
18
|
+
render(): ReplyResponse;
|
|
19
|
+
}
|
|
20
|
+
declare class NotOwner extends GateNotice {
|
|
21
|
+
constructor(message?: string);
|
|
22
|
+
}
|
|
23
|
+
declare class NotInGuild extends GateNotice {
|
|
24
|
+
constructor(message?: string);
|
|
25
|
+
}
|
|
26
|
+
declare class NotInDm extends GateNotice {
|
|
27
|
+
constructor(message?: string);
|
|
28
|
+
}
|
|
29
|
+
declare class OnCooldown extends GateNotice {
|
|
30
|
+
readonly resetAt: EpochMs;
|
|
31
|
+
constructor(resetAt: EpochMs, message?: string);
|
|
32
|
+
}
|
|
33
|
+
declare class NotAllowed extends Notice {
|
|
34
|
+
constructor();
|
|
35
|
+
render(): ReplyResponse;
|
|
36
|
+
}
|
|
37
|
+
declare class NeedsAny extends Notice {
|
|
38
|
+
private readonly summaries;
|
|
39
|
+
constructor(summaries: readonly string[]);
|
|
40
|
+
render(): ReplyResponse;
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/metadataKeys.d.ts
|
|
44
|
+
declare enum InteractionRoutes {
|
|
45
|
+
Slash = "slash",
|
|
46
|
+
Button = "button",
|
|
47
|
+
Modal = "modal",
|
|
48
|
+
StringMenu = "stringMenu",
|
|
49
|
+
UserMenu = "userMenu",
|
|
50
|
+
RoleMenu = "roleMenu",
|
|
51
|
+
ChannelMenu = "channelMenu",
|
|
52
|
+
MentionableMenu = "mentionableMenu",
|
|
53
|
+
MessageContextMenu = "messageContextMenu",
|
|
54
|
+
UserContextMenu = "userContextMenu",
|
|
55
|
+
Autocomplete = "autocomplete"
|
|
56
|
+
}
|
|
57
|
+
declare const InteractionMetadataKey: unique symbol;
|
|
58
|
+
declare const InteractionRouteKeys: Record<InteractionRoutes, symbol>;
|
|
59
|
+
declare const MiddlewareMetadataKey: unique symbol;
|
|
60
|
+
declare const EventMetadataKey: unique symbol;
|
|
61
|
+
declare const CommandMetadataKey: unique symbol;
|
|
62
|
+
declare const GatedMetadataKey: unique symbol;
|
|
63
|
+
declare const SubscribeMetadataKey: unique symbol;
|
|
64
|
+
//#endregion
|
|
45
65
|
//#region src/stops/NoticeCard.d.ts
|
|
46
66
|
/**
|
|
47
67
|
* Built fresh inside a {@link Notice}'s `render` to back its ComponentsV2 reply. The title renders as
|
|
@@ -79,5 +99,5 @@ type PageCursor<Prefix extends string> = CustomId<Prefix, {
|
|
|
79
99
|
/** Build the page cursor for a paginator. */
|
|
80
100
|
declare function pageCursor<Prefix extends string>(prefix: Prefix): PageCursor<Prefix>;
|
|
81
101
|
//#endregion
|
|
82
|
-
export { type AnyCustomId, ComponentDefsKey, type DecodedParams, type HasComponentDefs, NoticeCard, PAGE_MAX, type PageCursor, decodeFor, pageCursor, prefixOf, setBotColor };
|
|
102
|
+
export { type AnyCustomId, type CommandMeta, CommandMetadataKey, ComponentDefsKey, type DecodedParams, EventMetadataKey, type GateFitsWith, GateNotice, GatedMetadataKey, type HasComponentDefs, InteractionMetadataKey, InteractionRouteKeys, InteractionRoutes, MiddlewareMetadataKey, NeedsAny, NotAllowed, NotInDm, NotInGuild, NotOwner, NoticeCard, OnCooldown, PAGE_MAX, type PageCursor, SubscribeMetadataKey, decodeFor, pageCursor, pickNotice, prefixOf, routeIdOf, runGates, runHandlerGates, setBotColor };
|
|
83
103
|
//# sourceMappingURL=internal.index.d.mts.map
|
package/dist/internal.index.mjs
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as EventMetadataKey, D as InteractionRoutes, E as InteractionRouteKeys, O as MiddlewareMetadataKey, S as CommandMetadataKey, T as InteractionMetadataKey, _ as NoticeCard, a as discardCommits, b as setBotColor, c as runCheck, d as NeedsAny, f as NotAllowed, g as OnCooldown, h as NotOwner, i as pickNotice, k as SubscribeMetadataKey, l as runCommits, m as NotInGuild, n as decodeFor, p as NotInDm, r as prefixOf, t as CustomId, u as GateNotice, w as GatedMetadataKey } from "./CustomId-epJayEGO.mjs";
|
|
2
2
|
|
|
3
|
+
//#region src/gates/runGates.ts
|
|
4
|
+
function routeIdOf(handlerCtor) {
|
|
5
|
+
for (const [kind, key] of Object.entries(InteractionRouteKeys)) {
|
|
6
|
+
const routes = Reflect.getMetadata(key, handlerCtor);
|
|
7
|
+
if (routes?.length) return `${kind}:${routes.join(",")}`;
|
|
8
|
+
}
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Runs each gate's check in order, so the first refusal propagates to the dispatcher boundary. An effect
|
|
13
|
+
* gate's commit runs once the whole set passes.
|
|
14
|
+
*/
|
|
15
|
+
async function runGates(gates, ctx) {
|
|
16
|
+
try {
|
|
17
|
+
for (const gate of gates) await runCheck(gate, ctx);
|
|
18
|
+
await runCommits(ctx);
|
|
19
|
+
} finally {
|
|
20
|
+
discardCommits(ctx);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function runHandlerGates(handlerCtor, ctx) {
|
|
24
|
+
const gates = Reflect.getMetadata(GatedMetadataKey, handlerCtor);
|
|
25
|
+
if (!gates) return;
|
|
26
|
+
await runGates(gates, {
|
|
27
|
+
...ctx,
|
|
28
|
+
routeId: routeIdOf(handlerCtor)
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
3
33
|
//#region src/customId/routing.ts
|
|
4
34
|
/**
|
|
5
35
|
* The route decorators store a handler's customId definitions here so the component base can decode
|
|
@@ -19,5 +49,5 @@ function pageCursor(prefix) {
|
|
|
19
49
|
}
|
|
20
50
|
|
|
21
51
|
//#endregion
|
|
22
|
-
export { ComponentDefsKey, NoticeCard, PAGE_MAX, decodeFor, pageCursor, prefixOf, setBotColor };
|
|
52
|
+
export { CommandMetadataKey, ComponentDefsKey, EventMetadataKey, GateNotice, GatedMetadataKey, InteractionMetadataKey, InteractionRouteKeys, InteractionRoutes, MiddlewareMetadataKey, NeedsAny, NotAllowed, NotInDm, NotInGuild, NotOwner, NoticeCard, OnCooldown, PAGE_MAX, SubscribeMetadataKey, decodeFor, pageCursor, pickNotice, prefixOf, routeIdOf, runGates, runHandlerGates, setBotColor };
|
|
23
53
|
//# sourceMappingURL=internal.index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal.index.mjs","names":[],"sources":["../src/customId/routing.ts","../src/pagination/cursor.ts"],"sourcesContent":["import type { AnyCustomId } from './CustomId';\n\n/**\n * The route decorators store a handler's customId definitions 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 definitions 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 readonly __componentDefs?: Defs;\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), so each control uses a distinct slot.\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":"
|
|
1
|
+
{"version":3,"file":"internal.index.mjs","names":[],"sources":["../src/gates/runGates.ts","../src/customId/routing.ts","../src/pagination/cursor.ts"],"sourcesContent":["import { GatedMetadataKey, InteractionRouteKeys } from '@src/metadataKeys';\n\nimport { discardCommits, runCheck, runCommits } from './effects';\n\nimport type { Gate, GateContextBase } from './Gate';\n\n// the stable id a route decorator stored, e.g. slash:daily or button:confirm. null for a plain event handler.\nexport function routeIdOf(handlerCtor: object): string | null {\n for (const [kind, key] of Object.entries(InteractionRouteKeys)) {\n // justified: getMetadata returns any, this key only ever stores the route/prefix string array\n const routes = Reflect.getMetadata(key, handlerCtor) as string[] | undefined;\n if (routes?.length) return `${kind}:${routes.join(',')}`;\n }\n return null;\n}\n\n/**\n * Runs each gate's check in order, so the first refusal propagates to the dispatcher boundary. An effect\n * gate's commit runs once the whole set passes.\n */\nexport async function runGates(gates: readonly Gate<GateContextBase>[], ctx: GateContextBase): Promise<void> {\n try {\n for (const gate of gates) {\n await runCheck(gate, ctx);\n }\n await runCommits(ctx);\n } finally {\n discardCommits(ctx);\n }\n}\n\n// dispatchers call this before execute, inside the boundary, so a refusal renders or drops\nexport async function runHandlerGates(handlerCtor: object, ctx: GateContextBase): Promise<void> {\n // justified: getMetadata returns any, and this key only ever stores the @Gated gate array\n const gates = Reflect.getMetadata(GatedMetadataKey, handlerCtor) as readonly Gate<GateContextBase>[] | undefined;\n if (!gates) return;\n await runGates(gates, { ...ctx, routeId: routeIdOf(handlerCtor) });\n}\n","import type { AnyCustomId } from './CustomId';\n\n/**\n * The route decorators store a handler's customId definitions 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 definitions 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 readonly __componentDefs?: Defs;\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), so each control uses a distinct slot.\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":";;;AAOA,SAAgB,UAAU,aAAoC;CAC1D,KAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,oBAAoB,GAAG;EAE5D,MAAM,SAAS,QAAQ,YAAY,KAAK,WAAW;EACnD,IAAI,QAAQ,QAAQ,OAAO,GAAG,KAAK,GAAG,OAAO,KAAK,GAAG;CACzD;CACA,OAAO;AACX;;;;;AAMA,eAAsB,SAAS,OAAyC,KAAqC;CACzG,IAAI;EACA,KAAK,MAAM,QAAQ,OACf,MAAM,SAAS,MAAM,GAAG;EAE5B,MAAM,WAAW,GAAG;CACxB,UAAU;EACN,eAAe,GAAG;CACtB;AACJ;AAGA,eAAsB,gBAAgB,aAAqB,KAAqC;CAE5F,MAAM,QAAQ,QAAQ,YAAY,kBAAkB,WAAW;CAC/D,IAAI,CAAC,OAAO;CACZ,MAAM,SAAS,OAAO;EAAE,GAAG;EAAK,SAAS,UAAU,WAAW;CAAE,CAAC;AACrE;;;;;;;;;;AC7BA,MAAa,mBAAmB,OAAO,iCAAiC;;;;ACFxE,MAAa,WAAW;AAKxB,MAAM,WAAW;;AASjB,SAAgB,WAAkC,QAAoC;CAClF,OAAO,IAAI,SAAS,MAAM,CAAC,CAAC,IAAI,QAAQ,GAAG,QAAQ,CAAC,CAAC,IAAI,QAAQ,GAAG,QAAQ;AAChF"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seedcord/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.0-next.
|
|
4
|
+
"version": "0.1.0-next.3",
|
|
5
5
|
"description": "Transport-agnostic core for Seedcord bots",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -38,17 +38,21 @@
|
|
|
38
38
|
"LICENSE"
|
|
39
39
|
],
|
|
40
40
|
"peerDependencies": {
|
|
41
|
+
"reflect-metadata": "^0.2.2",
|
|
41
42
|
"typescript": "^6.0.3"
|
|
42
43
|
},
|
|
43
44
|
"dependencies": {
|
|
44
45
|
"@discordjs/builders": "^1.14.1",
|
|
45
46
|
"discord-api-types": "^0.38.49",
|
|
46
|
-
"@seedcord/errors": "0.3.0-next.
|
|
47
|
-
"@seedcord/types": "0.8.0-next.
|
|
47
|
+
"@seedcord/errors": "0.3.0-next.3",
|
|
48
|
+
"@seedcord/types": "0.8.0-next.4",
|
|
49
|
+
"@seedcord/utils": "0.8.0-next.4"
|
|
48
50
|
},
|
|
49
51
|
"devDependencies": {
|
|
52
|
+
"reflect-metadata": "^0.2.2",
|
|
50
53
|
"type-fest": "^5.7.0",
|
|
51
|
-
"@seedcord/eslint-config": "1.5.0-next.
|
|
54
|
+
"@seedcord/eslint-config": "1.5.0-next.3",
|
|
55
|
+
"@seedcord/rate-limiter": "0.1.0-next.1",
|
|
52
56
|
"@seedcord/tsconfig": "2.0.1",
|
|
53
57
|
"@seedcord/tsdown-config": "2.0.1"
|
|
54
58
|
},
|
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
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";
|
|
2
|
-
import { Snowflake } from "discord-api-types/v10";
|
|
3
|
-
|
|
4
|
-
//#region src/components/builderTypes.d.ts
|
|
5
|
-
/**
|
|
6
|
-
* Available Discord.js builder classes for use with BuilderComponent for commands, embeds, modals, etc.
|
|
7
|
-
*
|
|
8
|
-
* @internal
|
|
9
|
-
*/
|
|
10
|
-
declare const BuilderTypes: {
|
|
11
|
-
command: typeof SlashCommandBuilder;
|
|
12
|
-
context_menu: typeof ContextMenuCommandBuilder;
|
|
13
|
-
subcommand: typeof SlashCommandSubcommandBuilder;
|
|
14
|
-
group: typeof SlashCommandSubcommandGroupBuilder;
|
|
15
|
-
embed: typeof EmbedBuilder;
|
|
16
|
-
modal: typeof ModalBuilder;
|
|
17
|
-
label: typeof LabelBuilder;
|
|
18
|
-
text_input: typeof TextInputBuilder;
|
|
19
|
-
file_upload: typeof FileUploadBuilder;
|
|
20
|
-
checkbox: typeof CheckboxBuilder;
|
|
21
|
-
checkbox_group: typeof CheckboxGroupBuilder;
|
|
22
|
-
checkbox_group_option: typeof CheckboxGroupOptionBuilder;
|
|
23
|
-
radio_group: typeof RadioGroupBuilder;
|
|
24
|
-
radio_group_option: typeof RadioGroupOptionBuilder;
|
|
25
|
-
button: typeof ButtonBuilder;
|
|
26
|
-
menu_string: typeof StringSelectMenuBuilder;
|
|
27
|
-
menu_option_string: typeof StringSelectMenuOptionBuilder;
|
|
28
|
-
menu_user: typeof UserSelectMenuBuilder;
|
|
29
|
-
menu_channel: typeof ChannelSelectMenuBuilder;
|
|
30
|
-
menu_mentionable: typeof MentionableSelectMenuBuilder;
|
|
31
|
-
menu_role: typeof RoleSelectMenuBuilder;
|
|
32
|
-
container: typeof ContainerBuilder;
|
|
33
|
-
text_display: typeof TextDisplayBuilder;
|
|
34
|
-
file: typeof FileBuilder;
|
|
35
|
-
media: typeof MediaGalleryBuilder;
|
|
36
|
-
section: typeof SectionBuilder;
|
|
37
|
-
separator: typeof SeparatorBuilder;
|
|
38
|
-
};
|
|
39
|
-
/**
|
|
40
|
-
* Available Discord.js action row classes for use with RowComponent for Select Menus and Buttons
|
|
41
|
-
*
|
|
42
|
-
* @internal
|
|
43
|
-
*/
|
|
44
|
-
declare const RowTypes: {
|
|
45
|
-
button: typeof ActionRowBuilder<ButtonBuilder>;
|
|
46
|
-
menu_string: typeof ActionRowBuilder<StringSelectMenuBuilder>;
|
|
47
|
-
menu_user: typeof ActionRowBuilder<UserSelectMenuBuilder>;
|
|
48
|
-
menu_channel: typeof ActionRowBuilder<ChannelSelectMenuBuilder>;
|
|
49
|
-
menu_mentionable: typeof ActionRowBuilder<MentionableSelectMenuBuilder>;
|
|
50
|
-
menu_role: typeof ActionRowBuilder<RoleSelectMenuBuilder>;
|
|
51
|
-
};
|
|
52
|
-
/**
|
|
53
|
-
* Available Discord.js builder types for use with BuilderComponent
|
|
54
|
-
*/
|
|
55
|
-
type BuilderType = keyof typeof BuilderTypes;
|
|
56
|
-
/**
|
|
57
|
-
* @internal
|
|
58
|
-
*/
|
|
59
|
-
type InstantiatedBuilder<BuilderKey extends BuilderType> = InstanceType<(typeof BuilderTypes)[BuilderKey]>;
|
|
60
|
-
/**
|
|
61
|
-
* Available Discord.js action row types for use with RowComponent
|
|
62
|
-
*/
|
|
63
|
-
type RowType = keyof typeof RowTypes;
|
|
64
|
-
/**
|
|
65
|
-
* @internal
|
|
66
|
-
*/
|
|
67
|
-
type InstantiatedActionRow<RowKey extends RowType> = InstanceType<(typeof RowTypes)[RowKey]>;
|
|
68
|
-
//#endregion
|
|
69
|
-
//#region src/components/Component.d.ts
|
|
70
|
-
/**
|
|
71
|
-
* Base class for Discord component wrappers.
|
|
72
|
-
*
|
|
73
|
-
* @typeParam TComponent - The Discord.js component type being wrapped
|
|
74
|
-
*
|
|
75
|
-
* @internal
|
|
76
|
-
*/
|
|
77
|
-
declare abstract class BaseComponent<TComponent> {
|
|
78
|
-
private readonly _component;
|
|
79
|
-
protected constructor(ComponentClass: new () => TComponent);
|
|
80
|
-
/**
|
|
81
|
-
* Returns the live builder, ready to send in a Discord message or nest in another component.
|
|
82
|
-
*
|
|
83
|
-
* Configure it through `this.instance`. Reading this can apply the bot color (see
|
|
84
|
-
* {@link BuilderComponent}), so it has a side effect.
|
|
85
|
-
* @example new SomeComponent().component
|
|
86
|
-
*/
|
|
87
|
-
abstract get component(): InstantiatedBuilder<BuilderType> | InstantiatedActionRow<RowType>;
|
|
88
|
-
/**
|
|
89
|
-
* The wrapped builder, for calling Discord.js methods like setTitle() and setDescription() inside a subclass.
|
|
90
|
-
*
|
|
91
|
-
* @example this.instance.setTitle('My Modal')
|
|
92
|
-
*/
|
|
93
|
-
protected get instance(): TComponent;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Base class for Discord.js builder components
|
|
97
|
-
*
|
|
98
|
-
* Wraps Discord.js builders (SlashCommandBuilder, EmbedBuilder, etc.) with
|
|
99
|
-
* Seedcord-specific defaults and helper methods.
|
|
100
|
-
*
|
|
101
|
-
* @typeParam BuilderKey - The type of Discord.js builder being wrapped
|
|
102
|
-
*/
|
|
103
|
-
declare abstract class BuilderComponent<BuilderKey extends BuilderType> extends BaseComponent<InstantiatedBuilder<BuilderKey>> {
|
|
104
|
-
readonly type: BuilderKey;
|
|
105
|
-
private colorApplied;
|
|
106
|
-
protected constructor(type: BuilderKey);
|
|
107
|
-
get component(): InstantiatedBuilder<BuilderKey>;
|
|
108
|
-
private applyBotColor;
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Base class for Discord action row components
|
|
112
|
-
*
|
|
113
|
-
* Wraps Discord.js action row builder with Seedcord-specific defaults and helper methods.
|
|
114
|
-
*
|
|
115
|
-
* @typeParam RowKey - The Discord.js action row type being wrapped
|
|
116
|
-
*/
|
|
117
|
-
declare abstract class RowComponent<RowKey extends RowType> extends BaseComponent<InstantiatedActionRow<RowKey>> {
|
|
118
|
-
readonly type: RowKey;
|
|
119
|
-
protected constructor(type: RowKey);
|
|
120
|
-
get component(): InstantiatedActionRow<RowKey>;
|
|
121
|
-
}
|
|
122
|
-
//#endregion
|
|
123
|
-
//#region src/customId/Field.d.ts
|
|
124
|
-
/**
|
|
125
|
-
* One field in a customId shape, its wire kind plus the type it decodes to.
|
|
126
|
-
*
|
|
127
|
-
* @internal
|
|
128
|
-
*/
|
|
129
|
-
interface CustomIdField<Decoded> {
|
|
130
|
-
/** Which wire encoding this field uses. */
|
|
131
|
-
readonly kind: 'snowflake' | 'uuid' | 'int' | 'bool' | 'oneOf' | 'string';
|
|
132
|
-
/** Lower bound, for a bounded int field. */
|
|
133
|
-
readonly min?: number;
|
|
134
|
-
/** Upper bound, for a bounded int field. */
|
|
135
|
-
readonly max?: number;
|
|
136
|
-
/** The allowed values, for a oneOf field. */
|
|
137
|
-
readonly choices?: readonly string[];
|
|
138
|
-
/** Phantom only, carries the decoded type and is never set at runtime. */
|
|
139
|
-
readonly decoded?: Decoded;
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* The set of fields a customId carries, keyed by name.
|
|
143
|
-
*
|
|
144
|
-
* @internal
|
|
145
|
-
*/
|
|
146
|
-
type CustomIdShape = Record<string, CustomIdField<unknown>>;
|
|
147
|
-
/**
|
|
148
|
-
* The decoded result, each field name mapped to its decoded type.
|
|
149
|
-
*
|
|
150
|
-
* @internal
|
|
151
|
-
*/
|
|
152
|
-
type DecodedParams<Shape extends CustomIdShape> = { [Name in keyof Shape]: Shape[Name] extends CustomIdField<infer Decoded> ? Decoded : never };
|
|
153
|
-
//#endregion
|
|
154
|
-
//#region ../../node_modules/.pnpm/type-fest@5.7.0/node_modules/type-fest/source/non-empty-tuple.d.ts
|
|
155
|
-
/**
|
|
156
|
-
Matches any non-empty tuple.
|
|
157
|
-
|
|
158
|
-
@example
|
|
159
|
-
```
|
|
160
|
-
import type {NonEmptyTuple} from 'type-fest';
|
|
161
|
-
|
|
162
|
-
const sum = (...numbers: NonEmptyTuple<number>) => numbers.reduce((total, value) => total + value, 0);
|
|
163
|
-
|
|
164
|
-
sum(1, 2, 3);
|
|
165
|
-
// Ok
|
|
166
|
-
|
|
167
|
-
// @ts-expect-error
|
|
168
|
-
sum();
|
|
169
|
-
// Error: Expected at least 1 arguments, but got 0.
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
@see {@link RequireAtLeastOne} for objects
|
|
173
|
-
|
|
174
|
-
@category Array
|
|
175
|
-
*/
|
|
176
|
-
type NonEmptyTuple<T = unknown> = readonly [T, ...T[]];
|
|
177
|
-
//#endregion
|
|
178
|
-
//#region src/customId/CustomId.d.ts
|
|
179
|
-
/** Strip the layout hash off the routeKey to recover the stable prefix the controller routes by. @internal */
|
|
180
|
-
declare function prefixOf(wire: string): string;
|
|
181
|
-
/**
|
|
182
|
-
* A typed customId. The single source of truth shared by the component that mints it and the handler
|
|
183
|
-
* that reads it. This gives you typed reads on the `.customId` field in components. Values are packed into a compact wire string rather than plain stringified tokens, so the 100-char Discord limit goes further. More string per string, basically.
|
|
184
|
-
*
|
|
185
|
-
* @typeParam Prefix - The stable route prefix, e.g. 'approve'.
|
|
186
|
-
* @typeParam Shape - The accumulated fields, filled in by the chain.
|
|
187
|
-
*
|
|
188
|
-
* @example
|
|
189
|
-
* ```ts
|
|
190
|
-
* const ApproveId = new CustomId('approve')
|
|
191
|
-
* .snowflake('userId')
|
|
192
|
-
* .oneOf('action', ['approve', 'deny']);
|
|
193
|
-
*
|
|
194
|
-
* // Set the custom id on a button when creating it.
|
|
195
|
-
* new ButtonBuilder().setCustomId(ApproveId.encode({ userId: '123', action: 'approve' }));
|
|
196
|
-
*
|
|
197
|
-
* // reading in the handler: userId comes back a string
|
|
198
|
-
* const { userId, action } = this.params; // userId: string, action: 'approve' | 'deny'
|
|
199
|
-
* await this.event.guild?.members.fetch(userId);
|
|
200
|
-
* ```
|
|
201
|
-
*/
|
|
202
|
-
declare class CustomId<Prefix extends string, Shape extends CustomIdShape = {}> {
|
|
203
|
-
/** The stable route prefix, e.g. 'approve'. */
|
|
204
|
-
readonly prefix: Prefix;
|
|
205
|
-
/** Like a zod shape */
|
|
206
|
-
readonly shape: Shape;
|
|
207
|
-
/** The prefix plus a short hash of the shape, the part of the wire before the colon. */
|
|
208
|
-
readonly routeKey: string;
|
|
209
|
-
constructor(prefix: Prefix, shape?: Shape);
|
|
210
|
-
private add;
|
|
211
|
-
/**
|
|
212
|
-
* Add a Discord ID field, decoded as a string (the `Snowflake` type from discord-api-types).
|
|
213
|
-
*
|
|
214
|
-
* @example
|
|
215
|
-
* ```ts
|
|
216
|
-
* new CustomId('ban').snowflake('userId');
|
|
217
|
-
* ```
|
|
218
|
-
*/
|
|
219
|
-
snowflake<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<Snowflake>>>;
|
|
220
|
-
/**
|
|
221
|
-
* Add a UUID field, decoded as a lowercase uuid string.
|
|
222
|
-
*
|
|
223
|
-
* @example
|
|
224
|
-
* ```ts
|
|
225
|
-
* new CustomId('ticket').uuid('ticketId');
|
|
226
|
-
* ```
|
|
227
|
-
*/
|
|
228
|
-
uuid<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<string>>>;
|
|
229
|
-
/**
|
|
230
|
-
* Add an integer field with no bounds, for a value up to 2^53.
|
|
231
|
-
*
|
|
232
|
-
* @example
|
|
233
|
-
* ```ts
|
|
234
|
-
* new CustomId('shop').int('amount');
|
|
235
|
-
* ```
|
|
236
|
-
*/
|
|
237
|
-
int<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>>;
|
|
238
|
-
/**
|
|
239
|
-
* Add an integer field bounded by min and max, so it packs into fewer characters on the wire.
|
|
240
|
-
*
|
|
241
|
-
* @example
|
|
242
|
-
* ```ts
|
|
243
|
-
* new CustomId('paginate').int('page', 1, 50);
|
|
244
|
-
* ```
|
|
245
|
-
*/
|
|
246
|
-
int<Name extends string>(name: Name, min: number, max: number): CustomId<Prefix, Shape & Record<Name, CustomIdField<number>>>;
|
|
247
|
-
/**
|
|
248
|
-
* Add a boolean flag.
|
|
249
|
-
*
|
|
250
|
-
* @example
|
|
251
|
-
* ```ts
|
|
252
|
-
* new CustomId('settings').bool('silent');
|
|
253
|
-
* ```
|
|
254
|
-
*/
|
|
255
|
-
bool<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<boolean>>>;
|
|
256
|
-
/**
|
|
257
|
-
* Add a field that is one value from a fixed list, decoded as the literal union. No `as const` needed.
|
|
258
|
-
*
|
|
259
|
-
* @example
|
|
260
|
-
* ```ts
|
|
261
|
-
* new CustomId('poll').oneOf('choice', ['yes', 'no', 'abstain']);
|
|
262
|
-
* ```
|
|
263
|
-
*/
|
|
264
|
-
oneOf<Name extends string, const Choices extends NonEmptyTuple<string>>(name: Name, choices: Choices): CustomId<Prefix, Shape & Record<Name, CustomIdField<Choices[number]>>>;
|
|
265
|
-
/**
|
|
266
|
-
* Add a free short text field. Avoid it where possible, it cannot be packed so it costs the most wire space.
|
|
267
|
-
*
|
|
268
|
-
* @example
|
|
269
|
-
* ```ts
|
|
270
|
-
* new CustomId('note').str('message');
|
|
271
|
-
* ```
|
|
272
|
-
*/
|
|
273
|
-
str<Name extends string>(name: Name): CustomId<Prefix, Shape & Record<Name, CustomIdField<string>>>;
|
|
274
|
-
/**
|
|
275
|
-
* Mint a wire string from values. Throws if a value is out of its field's range or the wire is over 100 chars.
|
|
276
|
-
*
|
|
277
|
-
* @param values - One value per field, typed by the chain.
|
|
278
|
-
* @returns The wire string to put on the component's customId.
|
|
279
|
-
*/
|
|
280
|
-
encode(values: DecodedParams<Shape>): string;
|
|
281
|
-
/**
|
|
282
|
-
* Read a wire string back into values.
|
|
283
|
-
*
|
|
284
|
-
* - This will refuse with a default Notice when the shape changed since the wire was minted.
|
|
285
|
-
* - Or refuse with a different default Notice on a corrupt or foreign wire.
|
|
286
|
-
*
|
|
287
|
-
* @param wire - The customId string from the interaction.
|
|
288
|
-
* @returns The decoded values, typed by the chain.
|
|
289
|
-
*/
|
|
290
|
-
decode(wire: string): DecodedParams<Shape>;
|
|
291
|
-
/** True if this wire was minted from this customId's prefix, ignoring the shape hash. */
|
|
292
|
-
owns(wire: string): boolean;
|
|
293
|
-
}
|
|
294
|
-
/**
|
|
295
|
-
* Any customId, for places where the exact prefix and shape do not matter.
|
|
296
|
-
*
|
|
297
|
-
* @internal
|
|
298
|
-
*/
|
|
299
|
-
type AnyCustomId = CustomId<string, CustomIdShape>;
|
|
300
|
-
/**
|
|
301
|
-
* The outcome of decoding a wire against several customIds, the matched prefix paired with its values.
|
|
302
|
-
*
|
|
303
|
-
* @internal
|
|
304
|
-
*/
|
|
305
|
-
type DecodedRoute<Defs extends readonly AnyCustomId[]> = { [Index in keyof Defs]: Defs[Index] extends AnyCustomId ? {
|
|
306
|
-
readonly prefix: Defs[Index]['prefix'];
|
|
307
|
-
readonly params: DecodedParams<Defs[Index]['shape']>;
|
|
308
|
-
} : never }[number];
|
|
309
|
-
/**
|
|
310
|
-
* Find the customId whose prefix owns this wire, decode against it, and report which one matched.
|
|
311
|
-
*
|
|
312
|
-
* @internal
|
|
313
|
-
*/
|
|
314
|
-
declare function decodeFor<Defs extends readonly AnyCustomId[]>(defs: Defs, wire: string): DecodedRoute<Defs>;
|
|
315
|
-
//#endregion
|
|
316
|
-
export { CustomIdField as a, RowComponent as c, prefixOf as i, BuilderType as l, CustomId as n, DecodedParams as o, decodeFor as r, BuilderComponent as s, AnyCustomId as t, RowType as u };
|
|
317
|
-
//# sourceMappingURL=CustomId-BJF6mbJs.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CustomId-CqiuEllp.cjs","names":["SlashCommandBuilder","ContextMenuCommandBuilder","SlashCommandSubcommandBuilder","SlashCommandSubcommandGroupBuilder","EmbedBuilder","ModalBuilder","LabelBuilder","TextInputBuilder","FileUploadBuilder","CheckboxBuilder","CheckboxGroupBuilder","CheckboxGroupOptionBuilder","RadioGroupBuilder","RadioGroupOptionBuilder","ButtonBuilder","StringSelectMenuBuilder","StringSelectMenuOptionBuilder","UserSelectMenuBuilder","ChannelSelectMenuBuilder","MentionableSelectMenuBuilder","RoleSelectMenuBuilder","ContainerBuilder","TextDisplayBuilder","FileBuilder","MediaGalleryBuilder","SectionBuilder","SeparatorBuilder","ActionRowBuilder","SeedcordTypeError","SeedcordErrorCode","SeedcordRangeError","SlashCommandBuilder","ContextMenuCommandBuilder","InteractionContextType","EmbedBuilder","ContainerBuilder","TextDisplayBuilder","SeedcordRangeError","SeedcordErrorCode","SeedcordError","SeedcordErrorCode","SeedcordRangeError"],"sources":["../src/components/botColorHolder.ts","../src/components/builderTypes.ts","../src/components/colors.ts","../src/components/resolveColor.ts","../src/components/Component.ts","../src/stops/Notice.ts","../src/stops/NoticeCard.ts","../src/customId/Errors.ts","../src/customId/codec.ts","../src/customId/CustomId.ts"],"sourcesContent":["import type { BotColor } from './colors';\n\n// must be 'Default' so the container guard in applyBotColor leaves the accent unset\nconst DEFAULT_COLOR: BotColor = 'Default';\n\nlet current: BotColor = DEFAULT_COLOR;\n\n/** @internal */\nexport function setBotColor(color: BotColor | undefined): void {\n current = color ?? DEFAULT_COLOR;\n}\n\n/** @internal */\nexport function getBotColor(): BotColor {\n return current;\n}\n","import {\n ActionRowBuilder,\n ButtonBuilder,\n ChannelSelectMenuBuilder,\n CheckboxBuilder,\n CheckboxGroupBuilder,\n CheckboxGroupOptionBuilder,\n ContainerBuilder,\n ContextMenuCommandBuilder,\n EmbedBuilder,\n FileBuilder,\n FileUploadBuilder,\n LabelBuilder,\n MediaGalleryBuilder,\n MentionableSelectMenuBuilder,\n ModalBuilder,\n RadioGroupBuilder,\n RadioGroupOptionBuilder,\n RoleSelectMenuBuilder,\n SectionBuilder,\n SeparatorBuilder,\n SlashCommandBuilder,\n SlashCommandSubcommandBuilder,\n SlashCommandSubcommandGroupBuilder,\n StringSelectMenuBuilder,\n StringSelectMenuOptionBuilder,\n TextDisplayBuilder,\n TextInputBuilder,\n UserSelectMenuBuilder\n} from '@discordjs/builders';\n\n/**\n * Available Discord.js builder classes for use with BuilderComponent for commands, embeds, modals, etc.\n *\n * @internal\n */\nexport const BuilderTypes = {\n // Command Components\n command: SlashCommandBuilder,\n context_menu: ContextMenuCommandBuilder,\n subcommand: SlashCommandSubcommandBuilder,\n group: SlashCommandSubcommandGroupBuilder,\n\n // Embed Components\n embed: EmbedBuilder,\n\n // Modal Components\n modal: ModalBuilder,\n label: LabelBuilder,\n text_input: TextInputBuilder,\n file_upload: FileUploadBuilder,\n checkbox: CheckboxBuilder,\n checkbox_group: CheckboxGroupBuilder,\n checkbox_group_option: CheckboxGroupOptionBuilder,\n radio_group: RadioGroupBuilder,\n radio_group_option: RadioGroupOptionBuilder,\n\n // Action Row Components\n button: ButtonBuilder,\n menu_string: StringSelectMenuBuilder,\n menu_option_string: StringSelectMenuOptionBuilder,\n menu_user: UserSelectMenuBuilder,\n menu_channel: ChannelSelectMenuBuilder,\n menu_mentionable: MentionableSelectMenuBuilder,\n menu_role: RoleSelectMenuBuilder,\n\n // ComponentsV2\n container: ContainerBuilder,\n text_display: TextDisplayBuilder,\n file: FileBuilder,\n media: MediaGalleryBuilder,\n section: SectionBuilder,\n separator: SeparatorBuilder\n};\n\n/**\n * Available Discord.js action row classes for use with RowComponent for Select Menus and Buttons\n *\n * @internal\n */\nexport const RowTypes: {\n button: typeof ActionRowBuilder<ButtonBuilder>;\n menu_string: typeof ActionRowBuilder<StringSelectMenuBuilder>;\n menu_user: typeof ActionRowBuilder<UserSelectMenuBuilder>;\n menu_channel: typeof ActionRowBuilder<ChannelSelectMenuBuilder>;\n menu_mentionable: typeof ActionRowBuilder<MentionableSelectMenuBuilder>;\n menu_role: typeof ActionRowBuilder<RoleSelectMenuBuilder>;\n} = {\n button: ActionRowBuilder<ButtonBuilder>,\n menu_string: ActionRowBuilder<StringSelectMenuBuilder>,\n menu_user: ActionRowBuilder<UserSelectMenuBuilder>,\n menu_channel: ActionRowBuilder<ChannelSelectMenuBuilder>,\n menu_mentionable: ActionRowBuilder<MentionableSelectMenuBuilder>,\n menu_role: ActionRowBuilder<RoleSelectMenuBuilder>\n};\n\n/**\n * Available Discord.js builder types for use with BuilderComponent\n */\nexport type BuilderType = keyof typeof BuilderTypes;\n\n/**\n * @internal\n */\nexport type InstantiatedBuilder<BuilderKey extends BuilderType> = InstanceType<(typeof BuilderTypes)[BuilderKey]>;\n\n/**\n * Available Discord.js action row types for use with RowComponent\n */\nexport type RowType = keyof typeof RowTypes;\n\n/**\n * @internal\n */\nexport type InstantiatedActionRow<RowKey extends RowType> = InstanceType<(typeof RowTypes)[RowKey]>;\n","// Ported verbatim from discord.js (Apache-2.0), src/util/Colors.js.\nexport const Colors = {\n Aqua: 0x1a_bc_9c,\n Blue: 0x34_98_db,\n Blurple: 0x58_65_f2,\n DarkAqua: 0x11_80_6a,\n DarkBlue: 0x20_66_94,\n DarkButNotBlack: 0x2c_2f_33,\n DarkerGrey: 0x7f_8c_8d,\n DarkGold: 0xc2_7c_0e,\n DarkGreen: 0x1f_8b_4c,\n DarkGrey: 0x97_9c_9f,\n DarkNavy: 0x2c_3e_50,\n DarkOrange: 0xa8_43_00,\n DarkPurple: 0x71_36_8a,\n DarkRed: 0x99_2d_22,\n DarkVividPink: 0xad_14_57,\n Default: 0x00_00_00,\n Fuchsia: 0xeb_45_9e,\n Gold: 0xf1_c4_0f,\n Green: 0x57_f2_87,\n Grey: 0x95_a5_a6,\n Greyple: 0x99_aa_b5,\n LightGrey: 0xbc_c0_c0,\n LuminousVividPink: 0xe9_1e_63,\n Navy: 0x34_49_5e,\n NotQuiteBlack: 0x23_27_2a,\n Orange: 0xe6_7e_22,\n Purple: 0x9b_59_b6,\n Red: 0xed_42_45,\n White: 0xff_ff_ff,\n Yellow: 0xfe_e7_5c\n} as const;\n\n/** A discord.js color name, or `'Random'`. */\ntype ColorName = keyof typeof Colors | 'Random';\n\n/** Any color the bot color accepts: a name, a raw integer, a `#hex` string, or an rgb tuple. */\nexport type BotColor = ColorName | number | `#${string}` | readonly [number, number, number];\n","import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordRangeError, SeedcordTypeError } from '@seedcord/errors/internal';\n\nimport { Colors } from './colors';\n\nimport type { BotColor } from './colors';\n\nconst MAX_COLOR = 0xff_ff_ff;\nconst RED_SHIFT = 16;\nconst GREEN_SHIFT = 8;\n\nconst palette: Record<string, number | undefined> = Colors;\n\n/**\n * Resolves a {@link BotColor} to the integer Discord expects.\n *\n * Ported from discord.js (Apache-2.0), `resolveColor` in src/util/Util.js.\n */\nexport function resolveColor(color: BotColor): number {\n let resolved: number | undefined;\n\n if (typeof color === 'string') {\n if (color === 'Random') return Math.floor(Math.random() * (MAX_COLOR + 1));\n if (color === 'Default') return 0;\n if (/^#?[\\da-f]{6}$/i.test(color)) return Number.parseInt(color.replace('#', ''), 16);\n resolved = palette[color];\n } else if (typeof color === 'number') {\n resolved = color;\n } else {\n resolved = (color[0] << RED_SHIFT) + (color[1] << GREEN_SHIFT) + color[2];\n }\n\n if (resolved === undefined || !Number.isSafeInteger(resolved)) {\n throw new SeedcordTypeError(SeedcordErrorCode.ColorUnresolvable, [JSON.stringify(color)]);\n }\n if (resolved < 0 || resolved > MAX_COLOR) {\n throw new SeedcordRangeError(SeedcordErrorCode.ColorOutOfRange);\n }\n\n return resolved;\n}\n","import { ContainerBuilder, ContextMenuCommandBuilder, EmbedBuilder, SlashCommandBuilder } from '@discordjs/builders';\nimport { InteractionContextType } from 'discord-api-types/v10';\n\nimport { getBotColor } from './botColorHolder';\nimport { BuilderTypes, RowTypes } from './builderTypes';\nimport { resolveColor } from './resolveColor';\n\nimport type { BuilderType, InstantiatedActionRow, InstantiatedBuilder, RowType } from './builderTypes';\n\n/**\n * Base class for Discord component wrappers.\n *\n * @typeParam TComponent - The Discord.js component type being wrapped\n *\n * @internal\n */\nabstract class BaseComponent<TComponent> {\n private readonly _component: TComponent;\n\n protected constructor(ComponentClass: new () => TComponent) {\n this._component = new ComponentClass();\n }\n\n /**\n * Returns the live builder, ready to send in a Discord message or nest in another component.\n *\n * Configure it through `this.instance`. Reading this can apply the bot color (see\n * {@link BuilderComponent}), so it has a side effect.\n * @example new SomeComponent().component\n */\n public abstract get component(): InstantiatedBuilder<BuilderType> | InstantiatedActionRow<RowType>;\n\n /**\n * The wrapped builder, for calling Discord.js methods like setTitle() and setDescription() inside a subclass.\n *\n * @example this.instance.setTitle('My Modal')\n */\n protected get instance(): TComponent {\n return this._component;\n }\n}\n\n/**\n * Base class for Discord.js builder components\n *\n * Wraps Discord.js builders (SlashCommandBuilder, EmbedBuilder, etc.) with\n * Seedcord-specific defaults and helper methods.\n *\n * @typeParam BuilderKey - The type of Discord.js builder being wrapped\n */\nexport abstract class BuilderComponent<BuilderKey extends BuilderType> extends BaseComponent<\n InstantiatedBuilder<BuilderKey>\n> {\n private colorApplied = false;\n\n protected constructor(public readonly type: BuilderKey) {\n const ComponentClass = BuilderTypes[type] as unknown;\n super(ComponentClass as new () => InstantiatedBuilder<BuilderKey>);\n\n if (this.instance instanceof SlashCommandBuilder || this.instance instanceof ContextMenuCommandBuilder) {\n this.instance.setContexts(InteractionContextType.Guild);\n }\n }\n\n get component(): InstantiatedBuilder<BuilderKey> {\n this.applyBotColor();\n return this.instance;\n }\n\n // Resolving in the constructor would capture the default for a component built before setBotColor()\n // ran. The unset check keeps a color the subclass set for itself.\n private applyBotColor(): void {\n if (this.colorApplied) return;\n this.colorApplied = true;\n\n const color = getBotColor();\n if (this.instance instanceof EmbedBuilder) {\n if (this.instance.data.color === undefined) this.instance.setColor(resolveColor(color));\n } else if (this.instance instanceof ContainerBuilder) {\n const accent = this.instance.data.accent_color;\n if (accent === null || accent === undefined) {\n this.instance.setAccentColor(color === 'Default' ? undefined : resolveColor(color));\n }\n }\n }\n}\n\n/**\n * Base class for Discord action row components\n *\n * Wraps Discord.js action row builder with Seedcord-specific defaults and helper methods.\n *\n * @typeParam RowKey - The Discord.js action row type being wrapped\n */\nexport abstract class RowComponent<RowKey extends RowType> extends BaseComponent<InstantiatedActionRow<RowKey>> {\n protected constructor(public readonly type: RowKey) {\n const ComponentClass = RowTypes[type] as unknown;\n super(ComponentClass as new () => InstantiatedActionRow<RowKey>);\n }\n\n get component(): InstantiatedActionRow<RowKey> {\n return this.instance;\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';\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, so only the invoking user sees it. 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 instead of showing a neutral message.\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 rather than at construction time.\n */\n public abstract render(ctx: RenderContext): ReplyResponse;\n}\n","import { TextDisplayBuilder } from '@discordjs/builders';\n\nimport { BuilderComponent } from '@components/Component';\n\n/**\n * Built fresh inside a {@link Notice}'s `render` to back its ComponentsV2 reply. The title renders as\n * an h3 line with the description on the next line.\n */\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. The reply tells the user to run the command again.\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 * This should not happen in normal use, so it reports.\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, so a shape change moves the routeKey and decode catches an old wire as stale. bounded\n// fields (known range) fold into one base64 integer by mixed-radix packing, unbounded ones (free\n// string, unbounded int) trail it as delimited tokens.\n//\n// works on runtime values (unknown), the typed facade in CustomId.ts guarantees the types.\n\n// url-safe base64, one utf-16 unit per char so discord never rewrites it.\nconst ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';\nconst BASE = 64n;\nconst CHAR_TO_VALUE = new Map([...ALPHABET].map((char, index) => [char, index] as const));\n\n// unbounded fields trail after the packed block, split by this char and escaped by the next.\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// manual accumulator, never parseInt, which loses precision 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, so the field can 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\n// how many distinct values the field has. mixed-radix packing uses this as the field's base.\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 no choices here means a hand-built\n // corrupt shape rather than a real state.\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 routes a min-and-max int here, so a missing bound means a corrupt shape.\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// map a value to its slot, an integer in [0, radix). each kind maps differently.\nfunction boundedSlot(field: CustomIdField<unknown>, name: string, value: unknown): bigint {\n switch (field.kind) {\n case 'snowflake': {\n // a discord id is a non-negative integer string. reject non-strings here so a bad value\n // throws the branded out-of-range error rather than a raw BigInt() TypeError.\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, turn the slot back into the field's value.\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 int always encodes to at least one char, so an empty piece is a truncated wire\n if (piece === '') throw new InvalidCustomId('empty integer token');\n const decoded = zigzagDecode(base64ToBigint(piece));\n // an unbounded int is authored as a js number, so anything past 2^53 was tampered with.\n if (decoded > SAFE_MAX || decoded < SAFE_MIN) throw new InvalidCustomId('integer out of safe range');\n return Number(decoded);\n}\n\n/**\n * A short fingerprint of the shape. Change the shape and the hash changes, so an old customId no\n * longer matches the current routeKey and decode catches it as stale.\n *\n * @internal\n */\nexport function computeLayoutHash(shape: CustomIdShape): string {\n // a structured json signature, never a joined string, so a value holding a separator cannot collide.\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/**\n * Pack values into a body. Bounded fields fold into one integer, unbounded fields trail after it.\n *\n * @internal\n */\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 // fold each field in, multiply the running value by the field's radix then add its slot.\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\n// unpack the single bounded block back into result, reversing the field order.\nfunction unpackBounded(\n bounded: [string, CustomIdField<unknown>][],\n blob: string | undefined,\n result: Record<string, unknown>\n): void {\n // zero packs to one char, so an empty block means the body was truncated.\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 // leftover bits after every field is out means a corrupt block.\n if (packed !== 0n) throw new InvalidCustomId('leftover bits after unpacking');\n}\n\n/**\n * Reverse of encodeBody. Rejects any malformed or truncated body.\n *\n * @internal\n */\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, so there is nothing to split or unpack.\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 into a compact wire string rather than plain stringified tokens, so the 100-char Discord limit goes further. More string per string, basically.\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 * // reading 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 /** Like a zod shape */\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 would make the routeKey all-hash so prefixOf strips it to nothing and the\n // controller cannot route it, and a colon or control char would break 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 // a fresh immutable CustomId with one more field so we don't need a `as unknown as this` cast.\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 field's decoded type to never and overwrites the earlier field\n // at runtime, so reject it here at define time.\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 so it costs the most wire space.\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/**\n * Any customId, for places where the exact prefix and shape do not matter.\n *\n * @internal\n */\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/**\n * Find the customId whose prefix owns this wire, decode against it, and report which one matched.\n *\n * @internal\n */\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"],"mappings":"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"}
|