@moody-djs/prompts 1.0.1 → 1.0.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/index.d.mts CHANGED
@@ -1,5 +1,112 @@
1
- export { Prompt } from './Prompt.mjs';
2
- export { PromptComponentType, PromptContext, PromptState, PromptStateButtonComponent, PromptStateComponent, PromptStateComponentBase, PromptStateComponentBaseWithInteraction, PromptStateMessageCallback, PromptStateModalButtonComponent, PromptStateModalSelectMenuComponent, PromptStateSelectMenuComponent } from './types/prompt.types.mjs';
3
- export { PromptError, UserError } from './util/errors.mjs';
4
- import 'discord.js';
5
- import './types/util.types.mjs';
1
+ import { RepliableInteraction, EmbedBuilder, ButtonInteraction, ButtonBuilder, StringSelectMenuInteraction, StringSelectMenuBuilder, ModalSubmitInteraction, ModalBuilder } from 'discord.js';
2
+
3
+ type MaybePromise<T> = T | Promise<T>;
4
+
5
+ /** An enum containing the prompt component types that are supported */
6
+ declare enum PromptComponentType {
7
+ Button = 0,
8
+ ModalButton = 1,
9
+ SelectMenu = 2,
10
+ ModalSelectMenu = 3
11
+ }
12
+ type PromptContext<Context extends object, T = RepliableInteraction> = Context & {
13
+ interaction?: T;
14
+ previousStates: string[];
15
+ goBack: () => string;
16
+ genericError?: string;
17
+ };
18
+ interface ModalComponentReturnType<T, Interaction> {
19
+ button: T;
20
+ modal: ModalBuilder | ((interaction: Interaction) => MaybePromise<ModalBuilder | null>);
21
+ }
22
+ interface PromptStateComponentBase<Context extends object, Interaction = RepliableInteraction> {
23
+ callback: string | ((ctx: PromptContext<Context, Interaction>) => MaybePromise<string | undefined>);
24
+ }
25
+ interface PromptStateComponentBaseWithInteraction<Context extends object, Interaction = RepliableInteraction, AlternateInteraction = Interaction> {
26
+ callback: string | ((ctx: PromptContext<Context, Interaction>, interaction: AlternateInteraction) => MaybePromise<string | undefined>);
27
+ }
28
+ /** A prompt state that uses a button component */
29
+ interface PromptStateButtonComponent<T extends object> extends PromptStateComponentBase<T, ButtonInteraction> {
30
+ type: PromptComponentType.Button;
31
+ component: ButtonBuilder | ((ctx: PromptContext<T>) => MaybePromise<ButtonBuilder>);
32
+ }
33
+ /** A prompt state that contains a select menu */
34
+ interface PromptStateSelectMenuComponent<T extends object> extends PromptStateComponentBase<T, StringSelectMenuInteraction> {
35
+ type: PromptComponentType.SelectMenu;
36
+ component: StringSelectMenuBuilder | ((ctx: PromptContext<T>) => MaybePromise<StringSelectMenuBuilder>);
37
+ }
38
+ /** A prompt state that uses a modal that is opened by a button */
39
+ interface PromptStateModalButtonComponent<T extends object> extends PromptStateComponentBaseWithInteraction<T, ButtonInteraction, ModalSubmitInteraction> {
40
+ type: PromptComponentType.ModalButton;
41
+ component: ModalComponentReturnType<ButtonBuilder, ButtonInteraction> | ((ctx: PromptContext<T>) => MaybePromise<ModalComponentReturnType<ButtonBuilder, ButtonInteraction>>);
42
+ }
43
+ /** A prompt state that is a modal opened by a select menu component */
44
+ interface PromptStateModalSelectMenuComponent<T extends object> extends PromptStateComponentBaseWithInteraction<T, StringSelectMenuInteraction, ModalSubmitInteraction | null> {
45
+ type: PromptComponentType.ModalSelectMenu;
46
+ component: ModalComponentReturnType<StringSelectMenuBuilder, StringSelectMenuInteraction> | ((ctx: PromptContext<T>) => MaybePromise<ModalComponentReturnType<StringSelectMenuBuilder, StringSelectMenuInteraction>>);
47
+ }
48
+ /** A type representing a prompt state component, used when defining the components added for a prompt state */
49
+ type PromptStateComponent<T extends object> = PromptStateButtonComponent<T> | PromptStateSelectMenuComponent<T> | PromptStateModalSelectMenuComponent<T> | PromptStateModalButtonComponent<T>;
50
+ /** A prompt state message callback */
51
+ interface PromptStateMessageCallback<T extends object> {
52
+ ephemeral: boolean;
53
+ content?: string | ((ctx: PromptContext<T>) => MaybePromise<string | undefined>);
54
+ embeds: EmbedBuilder[] | ((ctx: PromptContext<T>) => MaybePromise<EmbedBuilder[]>);
55
+ components: PromptStateComponent<T>[][] | ((ctx: PromptContext<T>) => MaybePromise<PromptStateComponent<T>[][]>);
56
+ }
57
+ /**
58
+ * A type representing a prompt state that is possible
59
+ * @param T The type of the prompt context
60
+ */
61
+ interface PromptState<T extends object> {
62
+ name: string;
63
+ timeout?: number;
64
+ onEntered?: (ctx: PromptContext<T>) => MaybePromise<string | undefined>;
65
+ message: PromptStateMessageCallback<T> | ((ctx: PromptContext<T>) => MaybePromise<PromptStateMessageCallback<T>>);
66
+ }
67
+
68
+ /**
69
+ * A prompt that allows you to create a sequence of states that a user can go through
70
+ * with discord.js buttons and select menus.
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * const prompt = new Prompt<ContextType>(defaults, initialState.name, [...]);
75
+ * await prompt.start(interaction);
76
+ * ```
77
+ */
78
+ declare class Prompt<T extends object> {
79
+ initialState: string;
80
+ /** The current context of this prompt */
81
+ private context;
82
+ /** The current state */
83
+ private currentState?;
84
+ /** All components for this prompt */
85
+ private components;
86
+ /** The interaction collector */
87
+ private collector?;
88
+ /** The states represented in a map */
89
+ states: Map<string, PromptState<T>>;
90
+ /** Creates the prompt with a given set of states */
91
+ constructor(defaults: T, initialState: string, states: PromptState<T>[]);
92
+ /**
93
+ * Starts the prompt with a given interaction
94
+ * @param interaction The interaction starting off the sequence
95
+ * @returns {boolean} If true, the prompt started successfully
96
+ */
97
+ start(interaction: RepliableInteraction): Promise<boolean>;
98
+ private changeState;
99
+ private handleCollect;
100
+ private prepareMessageOptions;
101
+ private getNewStateFromCallback;
102
+ private formatComponents;
103
+ }
104
+
105
+ declare class PromptError extends Error {
106
+ constructor(message: string);
107
+ }
108
+ declare class UserError extends Error {
109
+ constructor(message: string);
110
+ }
111
+
112
+ export { Prompt, PromptComponentType, type PromptContext, PromptError, type PromptState, type PromptStateButtonComponent, type PromptStateComponent, type PromptStateComponentBase, type PromptStateComponentBaseWithInteraction, type PromptStateMessageCallback, type PromptStateModalButtonComponent, type PromptStateModalSelectMenuComponent, type PromptStateSelectMenuComponent, UserError };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,112 @@
1
- export { Prompt } from './Prompt.js';
2
- export { PromptComponentType, PromptContext, PromptState, PromptStateButtonComponent, PromptStateComponent, PromptStateComponentBase, PromptStateComponentBaseWithInteraction, PromptStateMessageCallback, PromptStateModalButtonComponent, PromptStateModalSelectMenuComponent, PromptStateSelectMenuComponent } from './types/prompt.types.js';
3
- export { PromptError, UserError } from './util/errors.js';
4
- import 'discord.js';
5
- import './types/util.types.js';
1
+ import { RepliableInteraction, EmbedBuilder, ButtonInteraction, ButtonBuilder, StringSelectMenuInteraction, StringSelectMenuBuilder, ModalSubmitInteraction, ModalBuilder } from 'discord.js';
2
+
3
+ type MaybePromise<T> = T | Promise<T>;
4
+
5
+ /** An enum containing the prompt component types that are supported */
6
+ declare enum PromptComponentType {
7
+ Button = 0,
8
+ ModalButton = 1,
9
+ SelectMenu = 2,
10
+ ModalSelectMenu = 3
11
+ }
12
+ type PromptContext<Context extends object, T = RepliableInteraction> = Context & {
13
+ interaction?: T;
14
+ previousStates: string[];
15
+ goBack: () => string;
16
+ genericError?: string;
17
+ };
18
+ interface ModalComponentReturnType<T, Interaction> {
19
+ button: T;
20
+ modal: ModalBuilder | ((interaction: Interaction) => MaybePromise<ModalBuilder | null>);
21
+ }
22
+ interface PromptStateComponentBase<Context extends object, Interaction = RepliableInteraction> {
23
+ callback: string | ((ctx: PromptContext<Context, Interaction>) => MaybePromise<string | undefined>);
24
+ }
25
+ interface PromptStateComponentBaseWithInteraction<Context extends object, Interaction = RepliableInteraction, AlternateInteraction = Interaction> {
26
+ callback: string | ((ctx: PromptContext<Context, Interaction>, interaction: AlternateInteraction) => MaybePromise<string | undefined>);
27
+ }
28
+ /** A prompt state that uses a button component */
29
+ interface PromptStateButtonComponent<T extends object> extends PromptStateComponentBase<T, ButtonInteraction> {
30
+ type: PromptComponentType.Button;
31
+ component: ButtonBuilder | ((ctx: PromptContext<T>) => MaybePromise<ButtonBuilder>);
32
+ }
33
+ /** A prompt state that contains a select menu */
34
+ interface PromptStateSelectMenuComponent<T extends object> extends PromptStateComponentBase<T, StringSelectMenuInteraction> {
35
+ type: PromptComponentType.SelectMenu;
36
+ component: StringSelectMenuBuilder | ((ctx: PromptContext<T>) => MaybePromise<StringSelectMenuBuilder>);
37
+ }
38
+ /** A prompt state that uses a modal that is opened by a button */
39
+ interface PromptStateModalButtonComponent<T extends object> extends PromptStateComponentBaseWithInteraction<T, ButtonInteraction, ModalSubmitInteraction> {
40
+ type: PromptComponentType.ModalButton;
41
+ component: ModalComponentReturnType<ButtonBuilder, ButtonInteraction> | ((ctx: PromptContext<T>) => MaybePromise<ModalComponentReturnType<ButtonBuilder, ButtonInteraction>>);
42
+ }
43
+ /** A prompt state that is a modal opened by a select menu component */
44
+ interface PromptStateModalSelectMenuComponent<T extends object> extends PromptStateComponentBaseWithInteraction<T, StringSelectMenuInteraction, ModalSubmitInteraction | null> {
45
+ type: PromptComponentType.ModalSelectMenu;
46
+ component: ModalComponentReturnType<StringSelectMenuBuilder, StringSelectMenuInteraction> | ((ctx: PromptContext<T>) => MaybePromise<ModalComponentReturnType<StringSelectMenuBuilder, StringSelectMenuInteraction>>);
47
+ }
48
+ /** A type representing a prompt state component, used when defining the components added for a prompt state */
49
+ type PromptStateComponent<T extends object> = PromptStateButtonComponent<T> | PromptStateSelectMenuComponent<T> | PromptStateModalSelectMenuComponent<T> | PromptStateModalButtonComponent<T>;
50
+ /** A prompt state message callback */
51
+ interface PromptStateMessageCallback<T extends object> {
52
+ ephemeral: boolean;
53
+ content?: string | ((ctx: PromptContext<T>) => MaybePromise<string | undefined>);
54
+ embeds: EmbedBuilder[] | ((ctx: PromptContext<T>) => MaybePromise<EmbedBuilder[]>);
55
+ components: PromptStateComponent<T>[][] | ((ctx: PromptContext<T>) => MaybePromise<PromptStateComponent<T>[][]>);
56
+ }
57
+ /**
58
+ * A type representing a prompt state that is possible
59
+ * @param T The type of the prompt context
60
+ */
61
+ interface PromptState<T extends object> {
62
+ name: string;
63
+ timeout?: number;
64
+ onEntered?: (ctx: PromptContext<T>) => MaybePromise<string | undefined>;
65
+ message: PromptStateMessageCallback<T> | ((ctx: PromptContext<T>) => MaybePromise<PromptStateMessageCallback<T>>);
66
+ }
67
+
68
+ /**
69
+ * A prompt that allows you to create a sequence of states that a user can go through
70
+ * with discord.js buttons and select menus.
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * const prompt = new Prompt<ContextType>(defaults, initialState.name, [...]);
75
+ * await prompt.start(interaction);
76
+ * ```
77
+ */
78
+ declare class Prompt<T extends object> {
79
+ initialState: string;
80
+ /** The current context of this prompt */
81
+ private context;
82
+ /** The current state */
83
+ private currentState?;
84
+ /** All components for this prompt */
85
+ private components;
86
+ /** The interaction collector */
87
+ private collector?;
88
+ /** The states represented in a map */
89
+ states: Map<string, PromptState<T>>;
90
+ /** Creates the prompt with a given set of states */
91
+ constructor(defaults: T, initialState: string, states: PromptState<T>[]);
92
+ /**
93
+ * Starts the prompt with a given interaction
94
+ * @param interaction The interaction starting off the sequence
95
+ * @returns {boolean} If true, the prompt started successfully
96
+ */
97
+ start(interaction: RepliableInteraction): Promise<boolean>;
98
+ private changeState;
99
+ private handleCollect;
100
+ private prepareMessageOptions;
101
+ private getNewStateFromCallback;
102
+ private formatComponents;
103
+ }
104
+
105
+ declare class PromptError extends Error {
106
+ constructor(message: string);
107
+ }
108
+ declare class UserError extends Error {
109
+ constructor(message: string);
110
+ }
111
+
112
+ export { Prompt, PromptComponentType, type PromptContext, PromptError, type PromptState, type PromptStateButtonComponent, type PromptStateComponent, type PromptStateComponentBase, type PromptStateComponentBaseWithInteraction, type PromptStateMessageCallback, type PromptStateModalButtonComponent, type PromptStateModalSelectMenuComponent, type PromptStateSelectMenuComponent, UserError };
package/dist/index.js CHANGED
@@ -1 +1,209 @@
1
- "use strict";var d=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var p=(r,t)=>d(r,"name",{value:t,configurable:!0});var C=(r,t)=>{for(var e in t)d(r,e,{get:t[e],enumerable:!0})},y=(r,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of b(t))!h.call(r,o)&&o!==e&&d(r,o,{get:()=>t[o],enumerable:!(n=M(t,o))||n.enumerable});return r};var f=r=>y(d({},"__esModule",{value:!0}),r);var P={};C(P,{Prompt:()=>g,PromptComponentType:()=>S,PromptError:()=>m,UserError:()=>x});module.exports=f(P);var c=require("discord.js");var S=(o=>(o[o.Button=0]="Button",o[o.ModalButton=1]="ModalButton",o[o.SelectMenu=2]="SelectMenu",o[o.ModalSelectMenu=3]="ModalSelectMenu",o))(S||{});var m=class r extends Error{static{p(this,"PromptError")}constructor(t){super(t),Error.captureStackTrace?.(this,r)}},x=class r extends Error{static{p(this,"UserError")}constructor(t){super(t),Error.captureStackTrace?.(this,r)}};var g=class{constructor(t,e,n){this.initialState=e;let o=[],a=p(()=>this.context.previousStates.pop()??this.initialState,"goBack");this.context={...t,previousStates:o,goBack:a},this.states=new Map(n.map(i=>[i.name,i]))}static{p(this,"Prompt")}context;currentState;components=new c.Collection;collector;states;async start(t){return this.context.interaction=t,this.changeState(this.initialState,t)}async changeState(t,e){let n=this.states.get(t);if(!n)return Promise.reject(new m(`State ${t} not found.`));this.context.previousStates.push(this.currentState?.name??this.initialState),this.currentState=n;let o=await n.onEntered?.(this.context);if(o)return this.changeState(o,e);let a=await this.prepareMessageOptions(n),i=e.replied||e.deferred?await e.editReply({embeds:a.embeds,components:a.components,content:a.content}):await e.reply(a);return this.collector&&this.collector.stop(),this.collector=i.createMessageComponentCollector({time:n.timeout||12e4,filter:p(s=>s.user.id===e.user.id,"filter")}),this.collector.on("collect",this.handleCollect.bind(this)),!0}async handleCollect(t){let e=this.components.get(t.customId);if(!e)throw new m(`Couldn't find component with customId: ${t.customId}`);if(e.type===1||e.type===3){let o=typeof e.component=="function"?await e.component(this.context):e.component,a=typeof o.modal=="function"?await o.modal(t):o.modal;if(!a){await t.deferUpdate(),this.collector?.stop(),this.context.interaction=t;let u=await this.getNewStateFromCallback(e)??this.currentState?.name;return u?void this.changeState(u,t):t.deleteReply()}let i=c.SnowflakeUtil.generate().toString();a.setCustomId(i),await t.showModal(a);let s=await t.awaitModalSubmit({time:3e5,filter:p(u=>u.user.id===t.user.id&&u.customId===i,"filter")}).catch(()=>null);if(!s)return;await s.deferUpdate(),this.collector?.stop(),this.context.interaction=s;let l=await this.getNewStateFromCallback(e,s)??this.currentState?.name;return l?void this.changeState(l,t):t.deleteReply()}await t.deferUpdate(),this.collector?.stop(),this.context.interaction=t;let n=await this.getNewStateFromCallback(e)??this.currentState?.name;if(!n)return t.deleteReply();this.changeState(n,t)}async prepareMessageOptions(t){let e=typeof t.message=="object"?t.message:await t.message(this.context);return{components:await this.formatComponents(e),fetchReply:!0,flags:e.ephemeral?c.MessageFlags.Ephemeral:0,content:typeof e.content=="function"?await e.content?.(this.context):e.content,embeds:Array.isArray(e.embeds)?e.embeds:await e.embeds(this.context)}}async getNewStateFromCallback(t,e){if(typeof t.callback=="string")return t.callback;if(t.type===1||t.type===3){if(!e)throw new m("No modal submit interaction found when required.");return t.callback(this.context,e)}return t.callback(this.context)}async formatComponents(t){let e=[],n=Array.isArray(t.components)?t.components:await t.components(this.context);this.components.clear();for(let o of n){let a=new c.ActionRowBuilder;for(let i of o){let s=typeof i.component=="function"?await i.component(this.context):i.component,l=c.SnowflakeUtil.generate().toString();"button"in s?(s.button.setCustomId(l),this.components.set(l,i),a.addComponents(s.button)):(s.setCustomId(l),this.components.set(l,i),a.addComponents(s))}e.push(a)}return e}};0&&(module.exports={Prompt,PromptComponentType,PromptError,UserError});
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var index_exports = {};
23
+ __export(index_exports, {
24
+ Prompt: () => Prompt,
25
+ PromptComponentType: () => PromptComponentType,
26
+ PromptError: () => PromptError,
27
+ UserError: () => UserError
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+
31
+ // src/Prompt.ts
32
+ var import_discord = require("discord.js");
33
+
34
+ // src/types/prompt.types.ts
35
+ var PromptComponentType = /* @__PURE__ */ ((PromptComponentType2) => {
36
+ PromptComponentType2[PromptComponentType2["Button"] = 0] = "Button";
37
+ PromptComponentType2[PromptComponentType2["ModalButton"] = 1] = "ModalButton";
38
+ PromptComponentType2[PromptComponentType2["SelectMenu"] = 2] = "SelectMenu";
39
+ PromptComponentType2[PromptComponentType2["ModalSelectMenu"] = 3] = "ModalSelectMenu";
40
+ return PromptComponentType2;
41
+ })(PromptComponentType || {});
42
+
43
+ // src/util/errors.ts
44
+ var PromptError = class _PromptError extends Error {
45
+ static {
46
+ __name(this, "PromptError");
47
+ }
48
+ constructor(message) {
49
+ super(message);
50
+ Error.captureStackTrace?.(this, _PromptError);
51
+ }
52
+ };
53
+ var UserError = class _UserError extends Error {
54
+ static {
55
+ __name(this, "UserError");
56
+ }
57
+ constructor(message) {
58
+ super(message);
59
+ Error.captureStackTrace?.(this, _UserError);
60
+ }
61
+ };
62
+
63
+ // src/Prompt.ts
64
+ var Prompt = class {
65
+ /** Creates the prompt with a given set of states */
66
+ constructor(defaults, initialState, states) {
67
+ this.initialState = initialState;
68
+ const previousStates = [];
69
+ const goBack = /* @__PURE__ */ __name(() => {
70
+ return this.context.previousStates.pop() ?? this.initialState;
71
+ }, "goBack");
72
+ this.context = { ...defaults, previousStates, goBack };
73
+ this.states = new Map(states.map((s) => [s.name, s]));
74
+ }
75
+ static {
76
+ __name(this, "Prompt");
77
+ }
78
+ /** The current context of this prompt */
79
+ context;
80
+ /** The current state */
81
+ currentState;
82
+ /** All components for this prompt */
83
+ components = new import_discord.Collection();
84
+ /** The interaction collector */
85
+ collector;
86
+ /** The states represented in a map */
87
+ states;
88
+ /**
89
+ * Starts the prompt with a given interaction
90
+ * @param interaction The interaction starting off the sequence
91
+ * @returns {boolean} If true, the prompt started successfully
92
+ */
93
+ async start(interaction) {
94
+ this.context.interaction = interaction;
95
+ return this.changeState(this.initialState, interaction);
96
+ }
97
+ async changeState(newState, interaction) {
98
+ const state = this.states.get(newState);
99
+ if (!state) return Promise.reject(new PromptError(`State ${newState} not found.`));
100
+ this.context.previousStates.push(this.currentState?.name ?? this.initialState);
101
+ this.currentState = state;
102
+ const shouldChangeState = await state.onEntered?.(this.context);
103
+ if (shouldChangeState) return this.changeState(shouldChangeState, interaction);
104
+ const messageOptions = await this.prepareMessageOptions(state);
105
+ const msg = interaction.replied || interaction.deferred ? await interaction.editReply({
106
+ embeds: messageOptions.embeds,
107
+ components: messageOptions.components,
108
+ content: messageOptions.content
109
+ }) : await interaction.reply(messageOptions);
110
+ if (this.collector) this.collector.stop();
111
+ this.collector = msg.createMessageComponentCollector({
112
+ time: state.timeout || 12e4,
113
+ filter: /* @__PURE__ */ __name((i) => i.user.id === interaction.user.id, "filter")
114
+ });
115
+ this.collector.on("collect", this.handleCollect.bind(this));
116
+ return true;
117
+ }
118
+ async handleCollect(interaction) {
119
+ const component = this.components.get(interaction.customId);
120
+ if (!component) throw new PromptError(`Couldn't find component with customId: ${interaction.customId}`);
121
+ if (component.type === 1 /* ModalButton */ || component.type === 3 /* ModalSelectMenu */) {
122
+ const childComponents = typeof component.component === "function" ? await component.component(this.context) : component.component;
123
+ const modal = typeof childComponents.modal === "function" ? await childComponents.modal(interaction) : childComponents.modal;
124
+ if (!modal) {
125
+ await interaction.deferUpdate();
126
+ this.collector?.stop();
127
+ this.context.interaction = interaction;
128
+ const newState3 = await this.getNewStateFromCallback(component) ?? this.currentState?.name;
129
+ if (!newState3) return interaction.deleteReply();
130
+ return void this.changeState(newState3, interaction);
131
+ }
132
+ const snowflake = import_discord.SnowflakeUtil.generate().toString();
133
+ modal.setCustomId(snowflake);
134
+ await interaction.showModal(modal);
135
+ const response = await interaction.awaitModalSubmit({
136
+ time: 3e5,
137
+ filter: /* @__PURE__ */ __name((i) => i.user.id === interaction.user.id && i.customId === snowflake, "filter")
138
+ }).catch(() => null);
139
+ if (!response) return;
140
+ await response.deferUpdate();
141
+ this.collector?.stop();
142
+ this.context.interaction = response;
143
+ const newState2 = await this.getNewStateFromCallback(component, response) ?? this.currentState?.name;
144
+ if (!newState2) return interaction.deleteReply();
145
+ return void this.changeState(newState2, interaction);
146
+ }
147
+ await interaction.deferUpdate();
148
+ this.collector?.stop();
149
+ this.context.interaction = interaction;
150
+ const newState = await this.getNewStateFromCallback(component) ?? this.currentState?.name;
151
+ if (!newState) return interaction.deleteReply();
152
+ return void this.changeState(newState, interaction);
153
+ }
154
+ async prepareMessageOptions(state) {
155
+ const messageData = typeof state.message === "object" ? state.message : await state.message(this.context);
156
+ const components = await this.formatComponents(messageData);
157
+ const messageOptions = {
158
+ components,
159
+ fetchReply: true,
160
+ flags: messageData.ephemeral ? import_discord.MessageFlags.Ephemeral : 0,
161
+ content: typeof messageData.content === "function" ? await messageData.content?.(this.context) : messageData.content,
162
+ embeds: Array.isArray(messageData.embeds) ? messageData.embeds : await messageData.embeds(this.context)
163
+ };
164
+ return messageOptions;
165
+ }
166
+ async getNewStateFromCallback(component, modalInteraction) {
167
+ if (typeof component.callback === "string") return component.callback;
168
+ if (component.type === 1 /* ModalButton */ || component.type === 3 /* ModalSelectMenu */) {
169
+ if (!modalInteraction) throw new PromptError("No modal submit interaction found when required.");
170
+ return component.callback(
171
+ this.context,
172
+ modalInteraction
173
+ );
174
+ }
175
+ return component.callback(
176
+ this.context
177
+ );
178
+ }
179
+ async formatComponents(data) {
180
+ const rows = [];
181
+ const components = Array.isArray(data.components) ? data.components : await data.components(this.context);
182
+ this.components.clear();
183
+ for (const row of components) {
184
+ const actionRow = new import_discord.ActionRowBuilder();
185
+ for (const component of row) {
186
+ const builder = typeof component.component === "function" ? await component.component(this.context) : component.component;
187
+ const id = import_discord.SnowflakeUtil.generate().toString();
188
+ if ("button" in builder) {
189
+ builder.button.setCustomId(id);
190
+ this.components.set(id, component);
191
+ actionRow.addComponents(builder.button);
192
+ } else {
193
+ builder.setCustomId(id);
194
+ this.components.set(id, component);
195
+ actionRow.addComponents(builder);
196
+ }
197
+ }
198
+ rows.push(actionRow);
199
+ }
200
+ return rows;
201
+ }
202
+ };
203
+ // Annotate the CommonJS export names for ESM import in node:
204
+ 0 && (module.exports = {
205
+ Prompt,
206
+ PromptComponentType,
207
+ PromptError,
208
+ UserError
209
+ });
package/dist/index.mjs CHANGED
@@ -1 +1,186 @@
1
- var g=Object.defineProperty;var s=(p,t)=>g(p,"name",{value:t,configurable:!0});import{ActionRowBuilder as M,Collection as b,MessageFlags as h,SnowflakeUtil as S}from"discord.js";var u=(o=>(o[o.Button=0]="Button",o[o.ModalButton=1]="ModalButton",o[o.SelectMenu=2]="SelectMenu",o[o.ModalSelectMenu=3]="ModalSelectMenu",o))(u||{});var l=class p extends Error{static{s(this,"PromptError")}constructor(t){super(t),Error.captureStackTrace?.(this,p)}},d=class p extends Error{static{s(this,"UserError")}constructor(t){super(t),Error.captureStackTrace?.(this,p)}};var x=class{constructor(t,e,r){this.initialState=e;let o=[],n=s(()=>this.context.previousStates.pop()??this.initialState,"goBack");this.context={...t,previousStates:o,goBack:n},this.states=new Map(r.map(a=>[a.name,a]))}static{s(this,"Prompt")}context;currentState;components=new b;collector;states;async start(t){return this.context.interaction=t,this.changeState(this.initialState,t)}async changeState(t,e){let r=this.states.get(t);if(!r)return Promise.reject(new l(`State ${t} not found.`));this.context.previousStates.push(this.currentState?.name??this.initialState),this.currentState=r;let o=await r.onEntered?.(this.context);if(o)return this.changeState(o,e);let n=await this.prepareMessageOptions(r),a=e.replied||e.deferred?await e.editReply({embeds:n.embeds,components:n.components,content:n.content}):await e.reply(n);return this.collector&&this.collector.stop(),this.collector=a.createMessageComponentCollector({time:r.timeout||12e4,filter:s(i=>i.user.id===e.user.id,"filter")}),this.collector.on("collect",this.handleCollect.bind(this)),!0}async handleCollect(t){let e=this.components.get(t.customId);if(!e)throw new l(`Couldn't find component with customId: ${t.customId}`);if(e.type===1||e.type===3){let o=typeof e.component=="function"?await e.component(this.context):e.component,n=typeof o.modal=="function"?await o.modal(t):o.modal;if(!n){await t.deferUpdate(),this.collector?.stop(),this.context.interaction=t;let m=await this.getNewStateFromCallback(e)??this.currentState?.name;return m?void this.changeState(m,t):t.deleteReply()}let a=S.generate().toString();n.setCustomId(a),await t.showModal(n);let i=await t.awaitModalSubmit({time:3e5,filter:s(m=>m.user.id===t.user.id&&m.customId===a,"filter")}).catch(()=>null);if(!i)return;await i.deferUpdate(),this.collector?.stop(),this.context.interaction=i;let c=await this.getNewStateFromCallback(e,i)??this.currentState?.name;return c?void this.changeState(c,t):t.deleteReply()}await t.deferUpdate(),this.collector?.stop(),this.context.interaction=t;let r=await this.getNewStateFromCallback(e)??this.currentState?.name;if(!r)return t.deleteReply();this.changeState(r,t)}async prepareMessageOptions(t){let e=typeof t.message=="object"?t.message:await t.message(this.context);return{components:await this.formatComponents(e),fetchReply:!0,flags:e.ephemeral?h.Ephemeral:0,content:typeof e.content=="function"?await e.content?.(this.context):e.content,embeds:Array.isArray(e.embeds)?e.embeds:await e.embeds(this.context)}}async getNewStateFromCallback(t,e){if(typeof t.callback=="string")return t.callback;if(t.type===1||t.type===3){if(!e)throw new l("No modal submit interaction found when required.");return t.callback(this.context,e)}return t.callback(this.context)}async formatComponents(t){let e=[],r=Array.isArray(t.components)?t.components:await t.components(this.context);this.components.clear();for(let o of r){let n=new M;for(let a of o){let i=typeof a.component=="function"?await a.component(this.context):a.component,c=S.generate().toString();"button"in i?(i.button.setCustomId(c),this.components.set(c,a),n.addComponents(i.button)):(i.setCustomId(c),this.components.set(c,a),n.addComponents(i))}e.push(n)}return e}};export{x as Prompt,u as PromptComponentType,l as PromptError,d as UserError};
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // src/Prompt.ts
5
+ import {
6
+ ActionRowBuilder,
7
+ Collection,
8
+ MessageFlags,
9
+ SnowflakeUtil
10
+ } from "discord.js";
11
+
12
+ // src/types/prompt.types.ts
13
+ var PromptComponentType = /* @__PURE__ */ ((PromptComponentType2) => {
14
+ PromptComponentType2[PromptComponentType2["Button"] = 0] = "Button";
15
+ PromptComponentType2[PromptComponentType2["ModalButton"] = 1] = "ModalButton";
16
+ PromptComponentType2[PromptComponentType2["SelectMenu"] = 2] = "SelectMenu";
17
+ PromptComponentType2[PromptComponentType2["ModalSelectMenu"] = 3] = "ModalSelectMenu";
18
+ return PromptComponentType2;
19
+ })(PromptComponentType || {});
20
+
21
+ // src/util/errors.ts
22
+ var PromptError = class _PromptError extends Error {
23
+ static {
24
+ __name(this, "PromptError");
25
+ }
26
+ constructor(message) {
27
+ super(message);
28
+ Error.captureStackTrace?.(this, _PromptError);
29
+ }
30
+ };
31
+ var UserError = class _UserError extends Error {
32
+ static {
33
+ __name(this, "UserError");
34
+ }
35
+ constructor(message) {
36
+ super(message);
37
+ Error.captureStackTrace?.(this, _UserError);
38
+ }
39
+ };
40
+
41
+ // src/Prompt.ts
42
+ var Prompt = class {
43
+ /** Creates the prompt with a given set of states */
44
+ constructor(defaults, initialState, states) {
45
+ this.initialState = initialState;
46
+ const previousStates = [];
47
+ const goBack = /* @__PURE__ */ __name(() => {
48
+ return this.context.previousStates.pop() ?? this.initialState;
49
+ }, "goBack");
50
+ this.context = { ...defaults, previousStates, goBack };
51
+ this.states = new Map(states.map((s) => [s.name, s]));
52
+ }
53
+ static {
54
+ __name(this, "Prompt");
55
+ }
56
+ /** The current context of this prompt */
57
+ context;
58
+ /** The current state */
59
+ currentState;
60
+ /** All components for this prompt */
61
+ components = new Collection();
62
+ /** The interaction collector */
63
+ collector;
64
+ /** The states represented in a map */
65
+ states;
66
+ /**
67
+ * Starts the prompt with a given interaction
68
+ * @param interaction The interaction starting off the sequence
69
+ * @returns {boolean} If true, the prompt started successfully
70
+ */
71
+ async start(interaction) {
72
+ this.context.interaction = interaction;
73
+ return this.changeState(this.initialState, interaction);
74
+ }
75
+ async changeState(newState, interaction) {
76
+ const state = this.states.get(newState);
77
+ if (!state) return Promise.reject(new PromptError(`State ${newState} not found.`));
78
+ this.context.previousStates.push(this.currentState?.name ?? this.initialState);
79
+ this.currentState = state;
80
+ const shouldChangeState = await state.onEntered?.(this.context);
81
+ if (shouldChangeState) return this.changeState(shouldChangeState, interaction);
82
+ const messageOptions = await this.prepareMessageOptions(state);
83
+ const msg = interaction.replied || interaction.deferred ? await interaction.editReply({
84
+ embeds: messageOptions.embeds,
85
+ components: messageOptions.components,
86
+ content: messageOptions.content
87
+ }) : await interaction.reply(messageOptions);
88
+ if (this.collector) this.collector.stop();
89
+ this.collector = msg.createMessageComponentCollector({
90
+ time: state.timeout || 12e4,
91
+ filter: /* @__PURE__ */ __name((i) => i.user.id === interaction.user.id, "filter")
92
+ });
93
+ this.collector.on("collect", this.handleCollect.bind(this));
94
+ return true;
95
+ }
96
+ async handleCollect(interaction) {
97
+ const component = this.components.get(interaction.customId);
98
+ if (!component) throw new PromptError(`Couldn't find component with customId: ${interaction.customId}`);
99
+ if (component.type === 1 /* ModalButton */ || component.type === 3 /* ModalSelectMenu */) {
100
+ const childComponents = typeof component.component === "function" ? await component.component(this.context) : component.component;
101
+ const modal = typeof childComponents.modal === "function" ? await childComponents.modal(interaction) : childComponents.modal;
102
+ if (!modal) {
103
+ await interaction.deferUpdate();
104
+ this.collector?.stop();
105
+ this.context.interaction = interaction;
106
+ const newState3 = await this.getNewStateFromCallback(component) ?? this.currentState?.name;
107
+ if (!newState3) return interaction.deleteReply();
108
+ return void this.changeState(newState3, interaction);
109
+ }
110
+ const snowflake = SnowflakeUtil.generate().toString();
111
+ modal.setCustomId(snowflake);
112
+ await interaction.showModal(modal);
113
+ const response = await interaction.awaitModalSubmit({
114
+ time: 3e5,
115
+ filter: /* @__PURE__ */ __name((i) => i.user.id === interaction.user.id && i.customId === snowflake, "filter")
116
+ }).catch(() => null);
117
+ if (!response) return;
118
+ await response.deferUpdate();
119
+ this.collector?.stop();
120
+ this.context.interaction = response;
121
+ const newState2 = await this.getNewStateFromCallback(component, response) ?? this.currentState?.name;
122
+ if (!newState2) return interaction.deleteReply();
123
+ return void this.changeState(newState2, interaction);
124
+ }
125
+ await interaction.deferUpdate();
126
+ this.collector?.stop();
127
+ this.context.interaction = interaction;
128
+ const newState = await this.getNewStateFromCallback(component) ?? this.currentState?.name;
129
+ if (!newState) return interaction.deleteReply();
130
+ return void this.changeState(newState, interaction);
131
+ }
132
+ async prepareMessageOptions(state) {
133
+ const messageData = typeof state.message === "object" ? state.message : await state.message(this.context);
134
+ const components = await this.formatComponents(messageData);
135
+ const messageOptions = {
136
+ components,
137
+ fetchReply: true,
138
+ flags: messageData.ephemeral ? MessageFlags.Ephemeral : 0,
139
+ content: typeof messageData.content === "function" ? await messageData.content?.(this.context) : messageData.content,
140
+ embeds: Array.isArray(messageData.embeds) ? messageData.embeds : await messageData.embeds(this.context)
141
+ };
142
+ return messageOptions;
143
+ }
144
+ async getNewStateFromCallback(component, modalInteraction) {
145
+ if (typeof component.callback === "string") return component.callback;
146
+ if (component.type === 1 /* ModalButton */ || component.type === 3 /* ModalSelectMenu */) {
147
+ if (!modalInteraction) throw new PromptError("No modal submit interaction found when required.");
148
+ return component.callback(
149
+ this.context,
150
+ modalInteraction
151
+ );
152
+ }
153
+ return component.callback(
154
+ this.context
155
+ );
156
+ }
157
+ async formatComponents(data) {
158
+ const rows = [];
159
+ const components = Array.isArray(data.components) ? data.components : await data.components(this.context);
160
+ this.components.clear();
161
+ for (const row of components) {
162
+ const actionRow = new ActionRowBuilder();
163
+ for (const component of row) {
164
+ const builder = typeof component.component === "function" ? await component.component(this.context) : component.component;
165
+ const id = SnowflakeUtil.generate().toString();
166
+ if ("button" in builder) {
167
+ builder.button.setCustomId(id);
168
+ this.components.set(id, component);
169
+ actionRow.addComponents(builder.button);
170
+ } else {
171
+ builder.setCustomId(id);
172
+ this.components.set(id, component);
173
+ actionRow.addComponents(builder);
174
+ }
175
+ }
176
+ rows.push(actionRow);
177
+ }
178
+ return rows;
179
+ }
180
+ };
181
+ export {
182
+ Prompt,
183
+ PromptComponentType,
184
+ PromptError,
185
+ UserError
186
+ };