@minesa-org/mini-interaction 0.0.5 → 0.0.6
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/builders/MiniContainerBuilder.d.ts +21 -21
- package/dist/builders/MiniContainerBuilder.js +16 -14
- package/dist/builders/TextInputBuilder.d.ts +57 -0
- package/dist/builders/TextInputBuilder.js +98 -0
- package/dist/builders/index.d.ts +4 -2
- package/dist/builders/index.js +2 -1
- package/dist/clients/MiniInteraction.d.ts +25 -0
- package/dist/clients/MiniInteraction.js +114 -4
- package/dist/index.d.ts +5 -1
- package/dist/index.js +2 -0
- package/dist/types/Commands.d.ts +11 -0
- package/dist/types/SeparatorSpacingSize.d.ts +2 -0
- package/dist/types/SeparatorSpacingSize.js +2 -0
- package/dist/utils/CommandInteractionOptions.d.ts +3 -1
- package/dist/utils/CommandInteractionOptions.js +6 -1
- package/dist/utils/MessageComponentInteraction.d.ts +13 -1
- package/dist/utils/MessageComponentInteraction.js +15 -0
- package/dist/utils/ModalSubmitInteraction.d.ts +28 -0
- package/dist/utils/ModalSubmitInteraction.js +74 -0
- package/dist/utils/interactionMessageHelpers.d.ts +5 -5
- package/dist/utils/interactionMessageHelpers.js +33 -8
- package/package.json +2 -1
|
@@ -20,30 +20,30 @@ export type MiniContentComponent = APIComponentInContainer;
|
|
|
20
20
|
/** Union of supported section accessory components. */
|
|
21
21
|
export type MiniSectionAccessoryComponent = APISectionAccessoryComponent;
|
|
22
22
|
/** Data accepted by the container builder constructor. */
|
|
23
|
-
export type
|
|
23
|
+
export type ContainerBuilderData = Partial<Omit<MiniContainerComponent, "components">> & {
|
|
24
24
|
components?: Array<MiniContentComponent | JSONEncodable<MiniContentComponent>>;
|
|
25
25
|
};
|
|
26
26
|
/** Data accepted by the section builder constructor. */
|
|
27
|
-
export type
|
|
27
|
+
export type SectionBuilderData = Partial<Omit<MiniSectionComponent, "components" | "accessory">> & {
|
|
28
28
|
components?: Array<MiniTextDisplayComponent | JSONEncodable<MiniTextDisplayComponent>>;
|
|
29
29
|
accessory?: MiniSectionAccessoryComponent | JSONEncodable<MiniSectionAccessoryComponent>;
|
|
30
30
|
};
|
|
31
31
|
/** Data accepted by the text display builder constructor. */
|
|
32
|
-
export type
|
|
32
|
+
export type TextDisplayBuilderData = Partial<MiniTextDisplayComponent>;
|
|
33
33
|
/** Data accepted by the separator builder constructor. */
|
|
34
|
-
export type
|
|
34
|
+
export type SeparatorBuilderData = Partial<MiniSeparatorComponent>;
|
|
35
35
|
/** Data accepted by the gallery builder constructor. */
|
|
36
|
-
export type
|
|
36
|
+
export type GalleryBuilderData = Partial<Omit<MiniGalleryComponent, "items">> & {
|
|
37
37
|
items?: Array<MiniGalleryItemComponent | JSONEncodable<MiniGalleryItemComponent>>;
|
|
38
38
|
};
|
|
39
39
|
/** Data accepted by the gallery item builder constructor. */
|
|
40
|
-
export type
|
|
40
|
+
export type GalleryItemBuilderData = Partial<MiniGalleryItemComponent>;
|
|
41
41
|
/** Data accepted by the thumbnail builder constructor. */
|
|
42
|
-
export type
|
|
42
|
+
export type ThumbnailBuilderData = Partial<MiniThumbnailComponent>;
|
|
43
43
|
/** Builder for structured message container payloads. */
|
|
44
|
-
export declare class
|
|
44
|
+
export declare class ContainerBuilder implements JSONEncodable<MiniContainerComponent> {
|
|
45
45
|
private data;
|
|
46
|
-
constructor(data?:
|
|
46
|
+
constructor(data?: ContainerBuilderData);
|
|
47
47
|
/** Replaces the components contained in the container. */
|
|
48
48
|
setComponents(components: Array<MiniContentComponent | JSONEncodable<MiniContentComponent>>): this;
|
|
49
49
|
/** Replaces the sections contained in the container. */
|
|
@@ -60,9 +60,9 @@ export declare class MiniContainerBuilder implements JSONEncodable<MiniContainer
|
|
|
60
60
|
toJSON(): MiniContainerComponent;
|
|
61
61
|
}
|
|
62
62
|
/** Builder for structured message sections. */
|
|
63
|
-
export declare class
|
|
63
|
+
export declare class SectionBuilder implements JSONEncodable<MiniSectionComponent> {
|
|
64
64
|
private data;
|
|
65
|
-
constructor(data?:
|
|
65
|
+
constructor(data?: SectionBuilderData);
|
|
66
66
|
/** Replaces the text components within the section. */
|
|
67
67
|
setComponents(components: Array<MiniTextDisplayComponent | JSONEncodable<MiniTextDisplayComponent>>): this;
|
|
68
68
|
/** Adds a text component to the section. */
|
|
@@ -73,18 +73,18 @@ export declare class MiniSectionBuilder implements JSONEncodable<MiniSectionComp
|
|
|
73
73
|
toJSON(): MiniSectionComponent;
|
|
74
74
|
}
|
|
75
75
|
/** Builder for structured message text display components. */
|
|
76
|
-
export declare class
|
|
76
|
+
export declare class TextDisplayBuilder implements JSONEncodable<MiniTextDisplayComponent> {
|
|
77
77
|
private data;
|
|
78
|
-
constructor(data?:
|
|
78
|
+
constructor(data?: TextDisplayBuilderData);
|
|
79
79
|
/** Sets or clears the primary text content. */
|
|
80
80
|
setContent(content: string | null | undefined): this;
|
|
81
81
|
/** Serialises the component into a structured message payload. */
|
|
82
82
|
toJSON(): MiniTextDisplayComponent;
|
|
83
83
|
}
|
|
84
84
|
/** Builder for structured message separator components. */
|
|
85
|
-
export declare class
|
|
85
|
+
export declare class SeparatorBuilder implements JSONEncodable<MiniSeparatorComponent> {
|
|
86
86
|
private data;
|
|
87
|
-
constructor(data?:
|
|
87
|
+
constructor(data?: SeparatorBuilderData);
|
|
88
88
|
/** Sets whether the separator should render a divider. */
|
|
89
89
|
setDivider(divider: boolean | null | undefined): this;
|
|
90
90
|
/** Sets the separator spacing value. */
|
|
@@ -93,9 +93,9 @@ export declare class MiniSeparatorBuilder implements JSONEncodable<MiniSeparator
|
|
|
93
93
|
toJSON(): MiniSeparatorComponent;
|
|
94
94
|
}
|
|
95
95
|
/** Builder for structured message thumbnails. */
|
|
96
|
-
export declare class
|
|
96
|
+
export declare class ThumbnailBuilder implements JSONEncodable<MiniThumbnailComponent> {
|
|
97
97
|
private data;
|
|
98
|
-
constructor(data?:
|
|
98
|
+
constructor(data?: ThumbnailBuilderData);
|
|
99
99
|
/** Sets the media payload for the thumbnail. */
|
|
100
100
|
setMedia(media: APIUnfurledMediaItem | null | undefined): this;
|
|
101
101
|
/** Sets the thumbnail description. */
|
|
@@ -106,9 +106,9 @@ export declare class MiniThumbnailBuilder implements JSONEncodable<MiniThumbnail
|
|
|
106
106
|
toJSON(): MiniThumbnailComponent;
|
|
107
107
|
}
|
|
108
108
|
/** Builder for structured message gallery items. */
|
|
109
|
-
export declare class
|
|
109
|
+
export declare class GalleryItemBuilder implements JSONEncodable<MiniGalleryItemComponent> {
|
|
110
110
|
private data;
|
|
111
|
-
constructor(data?:
|
|
111
|
+
constructor(data?: GalleryItemBuilderData);
|
|
112
112
|
/** Sets the media item payload. */
|
|
113
113
|
setMedia(media: APIUnfurledMediaItem | null | undefined): this;
|
|
114
114
|
/** Sets the media description. */
|
|
@@ -119,9 +119,9 @@ export declare class MiniGalleryItemBuilder implements JSONEncodable<MiniGallery
|
|
|
119
119
|
toJSON(): MiniGalleryItemComponent;
|
|
120
120
|
}
|
|
121
121
|
/** Builder for structured message gallery components. */
|
|
122
|
-
export declare class
|
|
122
|
+
export declare class GalleryBuilder implements JSONEncodable<MiniGalleryComponent> {
|
|
123
123
|
private data;
|
|
124
|
-
constructor(data?:
|
|
124
|
+
constructor(data?: GalleryBuilderData);
|
|
125
125
|
/** Replaces the gallery items. */
|
|
126
126
|
setItems(items: Array<MiniGalleryItemComponent | JSONEncodable<MiniGalleryItemComponent>>): this;
|
|
127
127
|
/** Adds a gallery item to the payload. */
|
|
@@ -9,7 +9,7 @@ function cloneAccessory(accessory) {
|
|
|
9
9
|
return { ...resolved };
|
|
10
10
|
}
|
|
11
11
|
/** Builder for structured message container payloads. */
|
|
12
|
-
export class
|
|
12
|
+
export class ContainerBuilder {
|
|
13
13
|
data;
|
|
14
14
|
constructor(data = {}) {
|
|
15
15
|
const components = data.components
|
|
@@ -71,7 +71,7 @@ export class MiniContainerBuilder {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
/** Builder for structured message sections. */
|
|
74
|
-
export class
|
|
74
|
+
export class SectionBuilder {
|
|
75
75
|
data;
|
|
76
76
|
constructor(data = {}) {
|
|
77
77
|
const components = data.components
|
|
@@ -112,9 +112,11 @@ export class MiniSectionBuilder {
|
|
|
112
112
|
/** Serialises the section into a structured message payload. */
|
|
113
113
|
toJSON() {
|
|
114
114
|
const components = this.data.components ?? [];
|
|
115
|
-
const accessory = this.data.accessory
|
|
115
|
+
const accessory = this.data.accessory
|
|
116
|
+
? { ...this.data.accessory }
|
|
117
|
+
: undefined;
|
|
116
118
|
if (!accessory) {
|
|
117
|
-
throw new Error("[
|
|
119
|
+
throw new Error("[SectionBuilder] accessory is required for sections");
|
|
118
120
|
}
|
|
119
121
|
return {
|
|
120
122
|
...this.data,
|
|
@@ -129,7 +131,7 @@ function cloneTextDisplayComponent(component) {
|
|
|
129
131
|
return { ...resolved };
|
|
130
132
|
}
|
|
131
133
|
/** Builder for structured message text display components. */
|
|
132
|
-
export class
|
|
134
|
+
export class TextDisplayBuilder {
|
|
133
135
|
data;
|
|
134
136
|
constructor(data = {}) {
|
|
135
137
|
this.data = {
|
|
@@ -150,7 +152,7 @@ export class MiniTextDisplayBuilder {
|
|
|
150
152
|
/** Serialises the component into a structured message payload. */
|
|
151
153
|
toJSON() {
|
|
152
154
|
if (!this.data.content) {
|
|
153
|
-
throw new Error("[
|
|
155
|
+
throw new Error("[TextDisplayBuilder] content is required for text displays");
|
|
154
156
|
}
|
|
155
157
|
return {
|
|
156
158
|
...this.data,
|
|
@@ -159,7 +161,7 @@ export class MiniTextDisplayBuilder {
|
|
|
159
161
|
}
|
|
160
162
|
}
|
|
161
163
|
/** Builder for structured message separator components. */
|
|
162
|
-
export class
|
|
164
|
+
export class SeparatorBuilder {
|
|
163
165
|
data;
|
|
164
166
|
constructor(data = {}) {
|
|
165
167
|
this.data = {
|
|
@@ -196,7 +198,7 @@ export class MiniSeparatorBuilder {
|
|
|
196
198
|
}
|
|
197
199
|
}
|
|
198
200
|
/** Builder for structured message thumbnails. */
|
|
199
|
-
export class
|
|
201
|
+
export class ThumbnailBuilder {
|
|
200
202
|
data;
|
|
201
203
|
constructor(data = {}) {
|
|
202
204
|
this.data = {
|
|
@@ -238,7 +240,7 @@ export class MiniThumbnailBuilder {
|
|
|
238
240
|
/** Serialises the thumbnail payload. */
|
|
239
241
|
toJSON() {
|
|
240
242
|
if (!this.data.media) {
|
|
241
|
-
throw new Error("[
|
|
243
|
+
throw new Error("[ThumbnailBuilder] media is required for thumbnails");
|
|
242
244
|
}
|
|
243
245
|
return {
|
|
244
246
|
...this.data,
|
|
@@ -247,7 +249,7 @@ export class MiniThumbnailBuilder {
|
|
|
247
249
|
}
|
|
248
250
|
}
|
|
249
251
|
/** Builder for structured message gallery items. */
|
|
250
|
-
export class
|
|
252
|
+
export class GalleryItemBuilder {
|
|
251
253
|
data;
|
|
252
254
|
constructor(data = {}) {
|
|
253
255
|
this.data = {
|
|
@@ -288,7 +290,7 @@ export class MiniGalleryItemBuilder {
|
|
|
288
290
|
/** Serialises the gallery item payload. */
|
|
289
291
|
toJSON() {
|
|
290
292
|
if (!this.data.media) {
|
|
291
|
-
throw new Error("[
|
|
293
|
+
throw new Error("[GalleryItemBuilder] media is required for gallery items");
|
|
292
294
|
}
|
|
293
295
|
return {
|
|
294
296
|
...this.data,
|
|
@@ -297,7 +299,7 @@ export class MiniGalleryItemBuilder {
|
|
|
297
299
|
}
|
|
298
300
|
}
|
|
299
301
|
/** Builder for structured message gallery components. */
|
|
300
|
-
export class
|
|
302
|
+
export class GalleryBuilder {
|
|
301
303
|
data;
|
|
302
304
|
constructor(data = {}) {
|
|
303
305
|
const items = data.items
|
|
@@ -324,7 +326,7 @@ export class MiniGalleryBuilder {
|
|
|
324
326
|
toJSON() {
|
|
325
327
|
const items = this.data.items ?? [];
|
|
326
328
|
if (items.length === 0) {
|
|
327
|
-
throw new Error("[
|
|
329
|
+
throw new Error("[GalleryBuilder] at least one gallery item is required");
|
|
328
330
|
}
|
|
329
331
|
return {
|
|
330
332
|
...this.data,
|
|
@@ -336,7 +338,7 @@ export class MiniGalleryBuilder {
|
|
|
336
338
|
function resolveGalleryItem(item) {
|
|
337
339
|
const resolved = resolveJSONEncodable(item);
|
|
338
340
|
if (!resolved.media) {
|
|
339
|
-
throw new Error("[
|
|
341
|
+
throw new Error("[GalleryBuilder] gallery items require media");
|
|
340
342
|
}
|
|
341
343
|
return {
|
|
342
344
|
...resolved,
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { TextInputStyle, type APITextInputComponent } from "discord-api-types/v10";
|
|
2
|
+
import type { JSONEncodable } from "./shared.js";
|
|
3
|
+
/** Shape describing initial text input data accepted by the builder. */
|
|
4
|
+
export type TextInputBuilderData = {
|
|
5
|
+
customId?: string;
|
|
6
|
+
label?: string;
|
|
7
|
+
style?: TextInputStyle;
|
|
8
|
+
minLength?: number;
|
|
9
|
+
maxLength?: number;
|
|
10
|
+
required?: boolean;
|
|
11
|
+
value?: string;
|
|
12
|
+
placeholder?: string;
|
|
13
|
+
};
|
|
14
|
+
/** Builder for Discord text input components used in modals. */
|
|
15
|
+
export declare class TextInputBuilder implements JSONEncodable<APITextInputComponent> {
|
|
16
|
+
private data;
|
|
17
|
+
/**
|
|
18
|
+
* Creates a new text input builder with optional seed data.
|
|
19
|
+
*/
|
|
20
|
+
constructor(data?: TextInputBuilderData);
|
|
21
|
+
/**
|
|
22
|
+
* Sets the custom identifier for this text input.
|
|
23
|
+
*/
|
|
24
|
+
setCustomId(customId: string): this;
|
|
25
|
+
/**
|
|
26
|
+
* Sets the label displayed above the text input.
|
|
27
|
+
*/
|
|
28
|
+
setLabel(label: string): this;
|
|
29
|
+
/**
|
|
30
|
+
* Sets the style of the text input (Short or Paragraph).
|
|
31
|
+
*/
|
|
32
|
+
setStyle(style: TextInputStyle): this;
|
|
33
|
+
/**
|
|
34
|
+
* Sets the minimum length of the input text.
|
|
35
|
+
*/
|
|
36
|
+
setMinLength(minLength: number): this;
|
|
37
|
+
/**
|
|
38
|
+
* Sets the maximum length of the input text.
|
|
39
|
+
*/
|
|
40
|
+
setMaxLength(maxLength: number): this;
|
|
41
|
+
/**
|
|
42
|
+
* Sets whether this text input is required.
|
|
43
|
+
*/
|
|
44
|
+
setRequired(required: boolean): this;
|
|
45
|
+
/**
|
|
46
|
+
* Sets the pre-filled value for this text input.
|
|
47
|
+
*/
|
|
48
|
+
setValue(value: string): this;
|
|
49
|
+
/**
|
|
50
|
+
* Sets the placeholder text shown when the input is empty.
|
|
51
|
+
*/
|
|
52
|
+
setPlaceholder(placeholder: string): this;
|
|
53
|
+
/**
|
|
54
|
+
* Serialises the builder into an API compatible text input payload.
|
|
55
|
+
*/
|
|
56
|
+
toJSON(): APITextInputComponent;
|
|
57
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { ComponentType, TextInputStyle, } from "discord-api-types/v10";
|
|
2
|
+
/** Builder for Discord text input components used in modals. */
|
|
3
|
+
export class TextInputBuilder {
|
|
4
|
+
data;
|
|
5
|
+
/**
|
|
6
|
+
* Creates a new text input builder with optional seed data.
|
|
7
|
+
*/
|
|
8
|
+
constructor(data = {}) {
|
|
9
|
+
this.data = {
|
|
10
|
+
customId: data.customId,
|
|
11
|
+
label: data.label,
|
|
12
|
+
style: data.style ?? TextInputStyle.Short,
|
|
13
|
+
minLength: data.minLength,
|
|
14
|
+
maxLength: data.maxLength,
|
|
15
|
+
required: data.required,
|
|
16
|
+
value: data.value,
|
|
17
|
+
placeholder: data.placeholder,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Sets the custom identifier for this text input.
|
|
22
|
+
*/
|
|
23
|
+
setCustomId(customId) {
|
|
24
|
+
this.data.customId = customId;
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Sets the label displayed above the text input.
|
|
29
|
+
*/
|
|
30
|
+
setLabel(label) {
|
|
31
|
+
this.data.label = label;
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Sets the style of the text input (Short or Paragraph).
|
|
36
|
+
*/
|
|
37
|
+
setStyle(style) {
|
|
38
|
+
this.data.style = style;
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Sets the minimum length of the input text.
|
|
43
|
+
*/
|
|
44
|
+
setMinLength(minLength) {
|
|
45
|
+
this.data.minLength = minLength;
|
|
46
|
+
return this;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Sets the maximum length of the input text.
|
|
50
|
+
*/
|
|
51
|
+
setMaxLength(maxLength) {
|
|
52
|
+
this.data.maxLength = maxLength;
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Sets whether this text input is required.
|
|
57
|
+
*/
|
|
58
|
+
setRequired(required) {
|
|
59
|
+
this.data.required = required;
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Sets the pre-filled value for this text input.
|
|
64
|
+
*/
|
|
65
|
+
setValue(value) {
|
|
66
|
+
this.data.value = value;
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Sets the placeholder text shown when the input is empty.
|
|
71
|
+
*/
|
|
72
|
+
setPlaceholder(placeholder) {
|
|
73
|
+
this.data.placeholder = placeholder;
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Serialises the builder into an API compatible text input payload.
|
|
78
|
+
*/
|
|
79
|
+
toJSON() {
|
|
80
|
+
if (!this.data.customId) {
|
|
81
|
+
throw new Error("[TextInputBuilder] custom_id is required.");
|
|
82
|
+
}
|
|
83
|
+
if (!this.data.label) {
|
|
84
|
+
throw new Error("[TextInputBuilder] label is required.");
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
type: ComponentType.TextInput,
|
|
88
|
+
custom_id: this.data.customId,
|
|
89
|
+
label: this.data.label,
|
|
90
|
+
style: this.data.style ?? TextInputStyle.Short,
|
|
91
|
+
min_length: this.data.minLength,
|
|
92
|
+
max_length: this.data.maxLength,
|
|
93
|
+
required: this.data.required,
|
|
94
|
+
value: this.data.value,
|
|
95
|
+
placeholder: this.data.placeholder,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
package/dist/builders/index.d.ts
CHANGED
|
@@ -11,10 +11,12 @@ export { ChannelSelectMenuBuilder } from "./ChannelSelectMenuBuilder.js";
|
|
|
11
11
|
export type { ChannelSelectMenuBuilderData } from "./ChannelSelectMenuBuilder.js";
|
|
12
12
|
export { ModalBuilder } from "./ModalBuilder.js";
|
|
13
13
|
export type { ModalBuilderData, ModalComponentLike } from "./ModalBuilder.js";
|
|
14
|
+
export { TextInputBuilder } from "./TextInputBuilder.js";
|
|
15
|
+
export type { TextInputBuilderData } from "./TextInputBuilder.js";
|
|
14
16
|
export { AutomodRuleBuilder } from "./AutomodRuleBuilder.js";
|
|
15
17
|
export type { AutomodRuleBuilderData } from "./AutomodRuleBuilder.js";
|
|
16
18
|
export { EmbedBuilder } from "./EmbedBuilder.js";
|
|
17
19
|
export type { EmbedBuilderData } from "./EmbedBuilder.js";
|
|
18
|
-
export {
|
|
19
|
-
export type {
|
|
20
|
+
export { ContainerBuilder, SectionBuilder, TextDisplayBuilder, SeparatorBuilder, GalleryBuilder, GalleryItemBuilder, ThumbnailBuilder, } from "./MiniContainerBuilder.js";
|
|
21
|
+
export type { ContainerBuilderData, SectionBuilderData, TextDisplayBuilderData, SeparatorBuilderData, GalleryBuilderData, GalleryItemBuilderData, ThumbnailBuilderData, MiniContainerComponent, MiniSectionComponent, MiniTextDisplayComponent, MiniSeparatorComponent, MiniGalleryComponent, MiniGalleryItemComponent, MiniThumbnailComponent, MiniContentComponent, MiniSectionAccessoryComponent, } from "./MiniContainerBuilder.js";
|
|
20
22
|
export type { JSONEncodable } from "./shared.js";
|
package/dist/builders/index.js
CHANGED
|
@@ -5,6 +5,7 @@ export { StringSelectMenuBuilder } from "./StringSelectMenuBuilder.js";
|
|
|
5
5
|
export { RoleSelectMenuBuilder } from "./RoleSelectMenuBuilder.js";
|
|
6
6
|
export { ChannelSelectMenuBuilder } from "./ChannelSelectMenuBuilder.js";
|
|
7
7
|
export { ModalBuilder } from "./ModalBuilder.js";
|
|
8
|
+
export { TextInputBuilder } from "./TextInputBuilder.js";
|
|
8
9
|
export { AutomodRuleBuilder } from "./AutomodRuleBuilder.js";
|
|
9
10
|
export { EmbedBuilder } from "./EmbedBuilder.js";
|
|
10
|
-
export {
|
|
11
|
+
export { ContainerBuilder, SectionBuilder, TextDisplayBuilder, SeparatorBuilder, GalleryBuilder, GalleryItemBuilder, ThumbnailBuilder, } from "./MiniContainerBuilder.js";
|
|
@@ -3,6 +3,7 @@ import { APIInteractionResponse, RESTPostAPIChatInputApplicationCommandsJSONBody
|
|
|
3
3
|
import type { MiniInteractionCommand } from "../types/Commands.js";
|
|
4
4
|
import { RoleConnectionMetadataTypes } from "../types/RoleConnectionMetadataTypes.js";
|
|
5
5
|
import { type MessageComponentInteraction } from "../utils/MessageComponentInteraction.js";
|
|
6
|
+
import { type ModalSubmitInteraction } from "../utils/ModalSubmitInteraction.js";
|
|
6
7
|
/** Configuration parameters for the MiniInteraction client. */
|
|
7
8
|
export type MiniInteractionOptions = {
|
|
8
9
|
applicationId: string;
|
|
@@ -41,6 +42,13 @@ export type MiniInteractionComponent = {
|
|
|
41
42
|
customId: string;
|
|
42
43
|
handler: MiniInteractionComponentHandler;
|
|
43
44
|
};
|
|
45
|
+
/** Handler signature invoked for Discord modal submit interactions. */
|
|
46
|
+
export type MiniInteractionModalHandler = (interaction: ModalSubmitInteraction) => Promise<APIInteractionResponse | void> | APIInteractionResponse | void;
|
|
47
|
+
/** Structure describing a modal handler mapped to a custom id. */
|
|
48
|
+
export type MiniInteractionModal = {
|
|
49
|
+
customId: string;
|
|
50
|
+
handler: MiniInteractionModalHandler;
|
|
51
|
+
};
|
|
44
52
|
/** Node.js HTTP handler compatible with frameworks like Express or Next.js API routes. */
|
|
45
53
|
export type MiniInteractionNodeHandler = (request: IncomingMessage, response: ServerResponse) => void;
|
|
46
54
|
/** Web Fetch API compatible request handler for platforms such as Cloudflare Workers. */
|
|
@@ -62,6 +70,7 @@ export declare class MiniInteraction {
|
|
|
62
70
|
private readonly componentsDirectory;
|
|
63
71
|
private readonly commands;
|
|
64
72
|
private readonly componentHandlers;
|
|
73
|
+
private readonly modalHandlers;
|
|
65
74
|
private commandsLoaded;
|
|
66
75
|
private loadCommandsPromise;
|
|
67
76
|
private componentsLoaded;
|
|
@@ -94,6 +103,18 @@ export declare class MiniInteraction {
|
|
|
94
103
|
* @param components - The component definitions to register.
|
|
95
104
|
*/
|
|
96
105
|
useComponents(components: MiniInteractionComponent[]): this;
|
|
106
|
+
/**
|
|
107
|
+
* Registers a single modal handler mapped to a custom identifier.
|
|
108
|
+
*
|
|
109
|
+
* @param modal - The modal definition to register.
|
|
110
|
+
*/
|
|
111
|
+
useModal(modal: MiniInteractionModal): this;
|
|
112
|
+
/**
|
|
113
|
+
* Registers multiple modal handlers in a single call.
|
|
114
|
+
*
|
|
115
|
+
* @param modals - The modal definitions to register.
|
|
116
|
+
*/
|
|
117
|
+
useModals(modals: MiniInteractionModal[]): this;
|
|
97
118
|
/**
|
|
98
119
|
* Recursively loads components from the configured components directory.
|
|
99
120
|
*
|
|
@@ -194,6 +215,10 @@ export declare class MiniInteraction {
|
|
|
194
215
|
* Handles execution of a message component interaction.
|
|
195
216
|
*/
|
|
196
217
|
private handleMessageComponent;
|
|
218
|
+
/**
|
|
219
|
+
* Handles execution of a modal submit interaction.
|
|
220
|
+
*/
|
|
221
|
+
private handleModalSubmit;
|
|
197
222
|
/**
|
|
198
223
|
* Handles execution of an application command interaction.
|
|
199
224
|
*/
|
|
@@ -7,6 +7,7 @@ import { verifyKey } from "discord-interactions";
|
|
|
7
7
|
import { DISCORD_BASE_URL } from "../utils/constants.js";
|
|
8
8
|
import { createCommandInteraction } from "../utils/CommandInteractionOptions.js";
|
|
9
9
|
import { createMessageComponentInteraction, } from "../utils/MessageComponentInteraction.js";
|
|
10
|
+
import { createModalSubmitInteraction, } from "../utils/ModalSubmitInteraction.js";
|
|
10
11
|
/** File extensions that are treated as loadable modules when auto-loading. */
|
|
11
12
|
const SUPPORTED_MODULE_EXTENSIONS = new Set([
|
|
12
13
|
".js",
|
|
@@ -29,6 +30,7 @@ export class MiniInteraction {
|
|
|
29
30
|
componentsDirectory;
|
|
30
31
|
commands = new Map();
|
|
31
32
|
componentHandlers = new Map();
|
|
33
|
+
modalHandlers = new Map();
|
|
32
34
|
commandsLoaded = false;
|
|
33
35
|
loadCommandsPromise = null;
|
|
34
36
|
componentsLoaded = false;
|
|
@@ -75,6 +77,18 @@ export class MiniInteraction {
|
|
|
75
77
|
console.warn(`[MiniInteraction] Command "${commandName}" already exists and will be overwritten.`);
|
|
76
78
|
}
|
|
77
79
|
this.commands.set(commandName, command);
|
|
80
|
+
// Register components exported with the command
|
|
81
|
+
if (command.components && Array.isArray(command.components)) {
|
|
82
|
+
for (const component of command.components) {
|
|
83
|
+
this.useComponent(component);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Register modals exported with the command
|
|
87
|
+
if (command.modals && Array.isArray(command.modals)) {
|
|
88
|
+
for (const modal of command.modals) {
|
|
89
|
+
this.useModal(modal);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
78
92
|
return this;
|
|
79
93
|
}
|
|
80
94
|
/**
|
|
@@ -118,6 +132,36 @@ export class MiniInteraction {
|
|
|
118
132
|
}
|
|
119
133
|
return this;
|
|
120
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Registers a single modal handler mapped to a custom identifier.
|
|
137
|
+
*
|
|
138
|
+
* @param modal - The modal definition to register.
|
|
139
|
+
*/
|
|
140
|
+
useModal(modal) {
|
|
141
|
+
const customId = modal?.customId;
|
|
142
|
+
if (!customId) {
|
|
143
|
+
throw new Error("[MiniInteraction] modal.customId is required");
|
|
144
|
+
}
|
|
145
|
+
if (typeof modal.handler !== "function") {
|
|
146
|
+
throw new Error("[MiniInteraction] modal.handler must be a function");
|
|
147
|
+
}
|
|
148
|
+
if (this.modalHandlers.has(customId)) {
|
|
149
|
+
console.warn(`[MiniInteraction] Modal "${customId}" already exists and will be overwritten.`);
|
|
150
|
+
}
|
|
151
|
+
this.modalHandlers.set(customId, modal.handler);
|
|
152
|
+
return this;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Registers multiple modal handlers in a single call.
|
|
156
|
+
*
|
|
157
|
+
* @param modals - The modal definitions to register.
|
|
158
|
+
*/
|
|
159
|
+
useModals(modals) {
|
|
160
|
+
for (const modal of modals) {
|
|
161
|
+
this.useModal(modal);
|
|
162
|
+
}
|
|
163
|
+
return this;
|
|
164
|
+
}
|
|
121
165
|
/**
|
|
122
166
|
* Recursively loads components from the configured components directory.
|
|
123
167
|
*
|
|
@@ -184,6 +228,18 @@ export class MiniInteraction {
|
|
|
184
228
|
continue;
|
|
185
229
|
}
|
|
186
230
|
this.commands.set(command.data.name, command);
|
|
231
|
+
// Register components exported from the command file
|
|
232
|
+
if (command.components && Array.isArray(command.components)) {
|
|
233
|
+
for (const component of command.components) {
|
|
234
|
+
this.useComponent(component);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// Register modals exported from the command file
|
|
238
|
+
if (command.modals && Array.isArray(command.modals)) {
|
|
239
|
+
for (const modal of command.modals) {
|
|
240
|
+
this.useModal(modal);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
187
243
|
}
|
|
188
244
|
this.commandsLoaded = true;
|
|
189
245
|
return this;
|
|
@@ -302,6 +358,9 @@ export class MiniInteraction {
|
|
|
302
358
|
if (interaction.type === InteractionType.MessageComponent) {
|
|
303
359
|
return this.handleMessageComponent(interaction);
|
|
304
360
|
}
|
|
361
|
+
if (interaction.type === InteractionType.ModalSubmit) {
|
|
362
|
+
return this.handleModalSubmit(interaction);
|
|
363
|
+
}
|
|
305
364
|
return {
|
|
306
365
|
status: 400,
|
|
307
366
|
body: {
|
|
@@ -542,9 +601,10 @@ export class MiniInteraction {
|
|
|
542
601
|
return;
|
|
543
602
|
}
|
|
544
603
|
if (!this.loadComponentsPromise) {
|
|
545
|
-
this.loadComponentsPromise =
|
|
546
|
-
this.
|
|
547
|
-
|
|
604
|
+
this.loadComponentsPromise =
|
|
605
|
+
this.loadComponentsFromDirectory().then(() => {
|
|
606
|
+
this.loadComponentsPromise = null;
|
|
607
|
+
});
|
|
548
608
|
}
|
|
549
609
|
await this.loadComponentsPromise;
|
|
550
610
|
}
|
|
@@ -583,7 +643,8 @@ export class MiniInteraction {
|
|
|
583
643
|
const candidates = [];
|
|
584
644
|
const isWithin = (parent, child) => {
|
|
585
645
|
const relative = path.relative(parent, child);
|
|
586
|
-
return relative === "" ||
|
|
646
|
+
return (relative === "" ||
|
|
647
|
+
(!relative.startsWith("..") && !path.isAbsolute(relative)));
|
|
587
648
|
};
|
|
588
649
|
const pushCandidate = (candidate) => {
|
|
589
650
|
if (!candidates.includes(candidate)) {
|
|
@@ -681,6 +742,55 @@ export class MiniInteraction {
|
|
|
681
742
|
};
|
|
682
743
|
}
|
|
683
744
|
}
|
|
745
|
+
/**
|
|
746
|
+
* Handles execution of a modal submit interaction.
|
|
747
|
+
*/
|
|
748
|
+
async handleModalSubmit(interaction) {
|
|
749
|
+
const customId = interaction?.data?.custom_id;
|
|
750
|
+
if (!customId) {
|
|
751
|
+
return {
|
|
752
|
+
status: 400,
|
|
753
|
+
body: {
|
|
754
|
+
error: "[MiniInteraction] Modal submit interaction is missing a custom_id",
|
|
755
|
+
},
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
const handler = this.modalHandlers.get(customId);
|
|
759
|
+
if (!handler) {
|
|
760
|
+
return {
|
|
761
|
+
status: 404,
|
|
762
|
+
body: {
|
|
763
|
+
error: `[MiniInteraction] No handler registered for modal "${customId}"`,
|
|
764
|
+
},
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
try {
|
|
768
|
+
const interactionWithHelpers = createModalSubmitInteraction(interaction);
|
|
769
|
+
const response = await handler(interactionWithHelpers);
|
|
770
|
+
const resolvedResponse = response ?? interactionWithHelpers.getResponse();
|
|
771
|
+
if (!resolvedResponse) {
|
|
772
|
+
return {
|
|
773
|
+
status: 500,
|
|
774
|
+
body: {
|
|
775
|
+
error: `[MiniInteraction] Modal "${customId}" did not return a response. ` +
|
|
776
|
+
"Return an APIInteractionResponse to acknowledge the interaction.",
|
|
777
|
+
},
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
return {
|
|
781
|
+
status: 200,
|
|
782
|
+
body: resolvedResponse,
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
catch (error) {
|
|
786
|
+
return {
|
|
787
|
+
status: 500,
|
|
788
|
+
body: {
|
|
789
|
+
error: `[MiniInteraction] Modal "${customId}" failed: ${String(error)}`,
|
|
790
|
+
},
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
}
|
|
684
794
|
/**
|
|
685
795
|
* Handles execution of an application command interaction.
|
|
686
796
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -7,11 +7,15 @@ export { CommandInteractionOptionResolver, createCommandInteraction, } from "./u
|
|
|
7
7
|
export type { CommandInteraction, MentionableOption, ResolvedUserOption, } from "./utils/CommandInteractionOptions.js";
|
|
8
8
|
export type { MiniInteractionFetchHandler, MiniInteractionNodeHandler, MiniInteractionHandlerResult, MiniInteractionRequest, MiniInteractionOptions, } from "./clients/MiniInteraction.js";
|
|
9
9
|
export type { MiniInteractionCommand, SlashCommandHandler, } from "./types/Commands.js";
|
|
10
|
-
export type { MiniInteractionComponent, MiniInteractionComponentHandler, } from "./clients/MiniInteraction.js";
|
|
10
|
+
export type { MiniInteractionComponent, MiniInteractionComponentHandler, MiniInteractionModal, MiniInteractionModalHandler, } from "./clients/MiniInteraction.js";
|
|
11
|
+
export type { MessageComponentInteraction } from "./utils/MessageComponentInteraction.js";
|
|
12
|
+
export type { ModalSubmitInteraction } from "./utils/ModalSubmitInteraction.js";
|
|
11
13
|
export { RoleConnectionMetadataTypes } from "./types/RoleConnectionMetadataTypes.js";
|
|
12
14
|
export { ChannelType } from "./types/ChannelType.js";
|
|
13
15
|
export { InteractionFollowUpFlags, InteractionReplyFlags, } from "./types/InteractionFlags.js";
|
|
14
16
|
export { ButtonStyle } from "./types/ButtonStyle.js";
|
|
17
|
+
export { SeparatorSpacingSize } from "./types/SeparatorSpacingSize.js";
|
|
18
|
+
export { TextInputStyle } from "discord-api-types/v10";
|
|
15
19
|
export { MiniPermFlags } from "./types/PermissionFlags.js";
|
|
16
20
|
export type { MiniComponentActionRow, MiniComponentMessageActionRow, } from "./types/ComponentTypes.js";
|
|
17
21
|
export * from "./builders/index.js";
|
package/dist/index.js
CHANGED
|
@@ -6,5 +6,7 @@ export { RoleConnectionMetadataTypes } from "./types/RoleConnectionMetadataTypes
|
|
|
6
6
|
export { ChannelType } from "./types/ChannelType.js";
|
|
7
7
|
export { InteractionFollowUpFlags, InteractionReplyFlags, } from "./types/InteractionFlags.js";
|
|
8
8
|
export { ButtonStyle } from "./types/ButtonStyle.js";
|
|
9
|
+
export { SeparatorSpacingSize } from "./types/SeparatorSpacingSize.js";
|
|
10
|
+
export { TextInputStyle } from "discord-api-types/v10";
|
|
9
11
|
export { MiniPermFlags } from "./types/PermissionFlags.js";
|
|
10
12
|
export * from "./builders/index.js";
|
package/dist/types/Commands.d.ts
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import type { APIInteractionResponse, RESTPostAPIChatInputApplicationCommandsJSONBody } from "discord-api-types/v10";
|
|
2
2
|
import type { CommandInteraction } from "../utils/CommandInteractionOptions.js";
|
|
3
|
+
import type { MiniInteractionComponent, MiniInteractionModal } from "../clients/MiniInteraction.js";
|
|
3
4
|
/** Handler signature for slash command executions within MiniInteraction. */
|
|
4
5
|
export type SlashCommandHandler = (interaction: CommandInteraction) => Promise<APIInteractionResponse | void> | APIInteractionResponse | void;
|
|
5
6
|
/** Structure representing a slash command definition and its runtime handler. */
|
|
6
7
|
export type MiniInteractionCommand = {
|
|
7
8
|
data: RESTPostAPIChatInputApplicationCommandsJSONBody;
|
|
8
9
|
handler: SlashCommandHandler;
|
|
10
|
+
/**
|
|
11
|
+
* Optional array of component handlers related to this command.
|
|
12
|
+
* These will be automatically registered when the command is loaded.
|
|
13
|
+
*/
|
|
14
|
+
components?: MiniInteractionComponent[];
|
|
15
|
+
/**
|
|
16
|
+
* Optional array of modal handlers related to this command.
|
|
17
|
+
* These will be automatically registered when the command is loaded.
|
|
18
|
+
*/
|
|
19
|
+
modals?: MiniInteractionModal[];
|
|
9
20
|
};
|
|
10
21
|
/** Map of command names to their registered MiniInteraction command definitions. */
|
|
11
22
|
export type MiniInteractionCommandsMap = Map<string, MiniInteractionCommand>;
|
|
@@ -132,7 +132,9 @@ export interface CommandInteraction extends Omit<APIChatInputApplicationCommandI
|
|
|
132
132
|
followUp(data: InteractionMessageData): APIInteractionResponseChannelMessageWithSource;
|
|
133
133
|
edit(data?: InteractionMessageData): APIInteractionResponseUpdateMessage;
|
|
134
134
|
deferReply(options?: DeferReplyOptions): APIInteractionResponseDeferredChannelMessageWithSource;
|
|
135
|
-
showModal(data: APIModalInteractionResponseCallbackData
|
|
135
|
+
showModal(data: APIModalInteractionResponseCallbackData | {
|
|
136
|
+
toJSON(): APIModalInteractionResponseCallbackData;
|
|
137
|
+
}): APIModalInteractionResponse;
|
|
136
138
|
}
|
|
137
139
|
/**
|
|
138
140
|
* Wraps a raw application command interaction with helper methods and option resolvers.
|
|
@@ -366,9 +366,14 @@ export function createCommandInteraction(interaction) {
|
|
|
366
366
|
: undefined);
|
|
367
367
|
},
|
|
368
368
|
showModal(data) {
|
|
369
|
+
const resolvedData = typeof data === "object" &&
|
|
370
|
+
"toJSON" in data &&
|
|
371
|
+
typeof data.toJSON === "function"
|
|
372
|
+
? data.toJSON()
|
|
373
|
+
: data;
|
|
369
374
|
return captureResponse({
|
|
370
375
|
type: InteractionResponseType.Modal,
|
|
371
|
-
data,
|
|
376
|
+
data: resolvedData,
|
|
372
377
|
});
|
|
373
378
|
},
|
|
374
379
|
};
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { type APIInteractionResponse, type APIInteractionResponseChannelMessageWithSource, type APIInteractionResponseDeferredChannelMessageWithSource, type APIInteractionResponseDeferredMessageUpdate, type APIInteractionResponseUpdateMessage, type APIMessageComponentInteraction } from "discord-api-types/v10";
|
|
1
|
+
import { type APIInteractionResponse, type APIInteractionResponseChannelMessageWithSource, type APIInteractionResponseDeferredChannelMessageWithSource, type APIInteractionResponseDeferredMessageUpdate, type APIInteractionResponseUpdateMessage, type APIMessageComponentInteraction, type APIModalInteractionResponse, type APIModalInteractionResponseCallbackData } from "discord-api-types/v10";
|
|
2
2
|
import { DeferReplyOptions, InteractionMessageData } from "./interactionMessageHelpers.js";
|
|
3
3
|
/**
|
|
4
4
|
* Represents a component interaction augmented with helper response methods.
|
|
5
|
+
*
|
|
6
|
+
* Note: The `values` property is available on select menu interactions (data.values).
|
|
7
|
+
* For button interactions, this property will be undefined.
|
|
5
8
|
*/
|
|
6
9
|
export type MessageComponentInteraction = APIMessageComponentInteraction & {
|
|
7
10
|
getResponse: () => APIInteractionResponse | null;
|
|
@@ -9,6 +12,15 @@ export type MessageComponentInteraction = APIMessageComponentInteraction & {
|
|
|
9
12
|
deferReply: (options?: DeferReplyOptions) => APIInteractionResponseDeferredChannelMessageWithSource;
|
|
10
13
|
update: (data?: InteractionMessageData) => APIInteractionResponseUpdateMessage;
|
|
11
14
|
deferUpdate: () => APIInteractionResponseDeferredMessageUpdate;
|
|
15
|
+
showModal: (data: APIModalInteractionResponseCallbackData | {
|
|
16
|
+
toJSON(): APIModalInteractionResponseCallbackData;
|
|
17
|
+
}) => APIModalInteractionResponse;
|
|
18
|
+
/**
|
|
19
|
+
* The selected values from a select menu interaction.
|
|
20
|
+
* This property is only present for select menu interactions.
|
|
21
|
+
* For button interactions, this will be undefined.
|
|
22
|
+
*/
|
|
23
|
+
values?: string[];
|
|
12
24
|
};
|
|
13
25
|
/**
|
|
14
26
|
* Wraps a raw component interaction with helper methods mirroring Discord's expected responses.
|
|
@@ -49,12 +49,27 @@ export function createMessageComponentInteraction(interaction) {
|
|
|
49
49
|
const deferUpdate = () => captureResponse({
|
|
50
50
|
type: InteractionResponseType.DeferredMessageUpdate,
|
|
51
51
|
});
|
|
52
|
+
const showModal = (data) => {
|
|
53
|
+
const resolvedData = typeof data === "object" &&
|
|
54
|
+
"toJSON" in data &&
|
|
55
|
+
typeof data.toJSON === "function"
|
|
56
|
+
? data.toJSON()
|
|
57
|
+
: data;
|
|
58
|
+
return captureResponse({
|
|
59
|
+
type: InteractionResponseType.Modal,
|
|
60
|
+
data: resolvedData,
|
|
61
|
+
});
|
|
62
|
+
};
|
|
52
63
|
const getResponse = () => capturedResponse;
|
|
64
|
+
// Extract values from select menu interactions
|
|
65
|
+
const values = "values" in interaction.data ? interaction.data.values : undefined;
|
|
53
66
|
return Object.assign(interaction, {
|
|
54
67
|
reply,
|
|
55
68
|
deferReply,
|
|
56
69
|
update,
|
|
57
70
|
deferUpdate,
|
|
71
|
+
showModal,
|
|
58
72
|
getResponse,
|
|
73
|
+
values,
|
|
59
74
|
});
|
|
60
75
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type APIInteractionResponse, type APIInteractionResponseChannelMessageWithSource, type APIInteractionResponseDeferredChannelMessageWithSource, type APIModalSubmitInteraction } from "discord-api-types/v10";
|
|
2
|
+
import { DeferReplyOptions, InteractionMessageData } from "./interactionMessageHelpers.js";
|
|
3
|
+
/**
|
|
4
|
+
* Represents a modal submit interaction augmented with helper response methods.
|
|
5
|
+
*/
|
|
6
|
+
export type ModalSubmitInteraction = APIModalSubmitInteraction & {
|
|
7
|
+
getResponse: () => APIInteractionResponse | null;
|
|
8
|
+
reply: (data: InteractionMessageData) => APIInteractionResponseChannelMessageWithSource;
|
|
9
|
+
deferReply: (options?: DeferReplyOptions) => APIInteractionResponseDeferredChannelMessageWithSource;
|
|
10
|
+
/**
|
|
11
|
+
* Helper method to get the value of a text input component by custom_id.
|
|
12
|
+
* @param customId - The custom_id of the text input component
|
|
13
|
+
* @returns The value of the text input, or undefined if not found
|
|
14
|
+
*/
|
|
15
|
+
getTextInputValue: (customId: string) => string | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Helper method to get all text input values as a map.
|
|
18
|
+
* @returns A map of custom_id to value for all text inputs
|
|
19
|
+
*/
|
|
20
|
+
getTextInputValues: () => Map<string, string>;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Wraps a raw modal submit interaction with helper methods.
|
|
24
|
+
*
|
|
25
|
+
* @param interaction - The raw interaction payload from Discord.
|
|
26
|
+
* @returns A helper-augmented interaction object.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createModalSubmitInteraction(interaction: APIModalSubmitInteraction): ModalSubmitInteraction;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { InteractionResponseType, } from "discord-api-types/v10";
|
|
2
|
+
import { normaliseInteractionMessageData, normaliseMessageFlags, } from "./interactionMessageHelpers.js";
|
|
3
|
+
/**
|
|
4
|
+
* Wraps a raw modal submit interaction with helper methods.
|
|
5
|
+
*
|
|
6
|
+
* @param interaction - The raw interaction payload from Discord.
|
|
7
|
+
* @returns A helper-augmented interaction object.
|
|
8
|
+
*/
|
|
9
|
+
export function createModalSubmitInteraction(interaction) {
|
|
10
|
+
let capturedResponse = null;
|
|
11
|
+
const captureResponse = (response) => {
|
|
12
|
+
capturedResponse = response;
|
|
13
|
+
return response;
|
|
14
|
+
};
|
|
15
|
+
const reply = (data) => {
|
|
16
|
+
const normalisedData = normaliseInteractionMessageData(data);
|
|
17
|
+
if (!normalisedData) {
|
|
18
|
+
throw new Error("[MiniInteraction] Modal submit replies require response data to be provided.");
|
|
19
|
+
}
|
|
20
|
+
return captureResponse({
|
|
21
|
+
type: InteractionResponseType.ChannelMessageWithSource,
|
|
22
|
+
data: normalisedData,
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
const deferReply = (options) => {
|
|
26
|
+
const flags = normaliseMessageFlags(options?.flags);
|
|
27
|
+
const response = flags !== undefined
|
|
28
|
+
? {
|
|
29
|
+
type: InteractionResponseType.DeferredChannelMessageWithSource,
|
|
30
|
+
data: { flags },
|
|
31
|
+
}
|
|
32
|
+
: {
|
|
33
|
+
type: InteractionResponseType.DeferredChannelMessageWithSource,
|
|
34
|
+
};
|
|
35
|
+
return captureResponse(response);
|
|
36
|
+
};
|
|
37
|
+
const getResponse = () => capturedResponse;
|
|
38
|
+
// Helper to extract text input values from modal components
|
|
39
|
+
const extractTextInputs = () => {
|
|
40
|
+
const textInputs = new Map();
|
|
41
|
+
for (const component of interaction.data.components) {
|
|
42
|
+
// Handle action rows
|
|
43
|
+
if ("components" in component && Array.isArray(component.components)) {
|
|
44
|
+
for (const child of component.components) {
|
|
45
|
+
if ("value" in child && "custom_id" in child) {
|
|
46
|
+
textInputs.set(child.custom_id, child.value);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Handle labeled components
|
|
51
|
+
else if ("component" in component) {
|
|
52
|
+
const labeledComponent = component.component;
|
|
53
|
+
if ("value" in labeledComponent && "custom_id" in labeledComponent) {
|
|
54
|
+
textInputs.set(labeledComponent.custom_id, labeledComponent.value);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return textInputs;
|
|
59
|
+
};
|
|
60
|
+
const textInputValues = extractTextInputs();
|
|
61
|
+
const getTextInputValue = (customId) => {
|
|
62
|
+
return textInputValues.get(customId);
|
|
63
|
+
};
|
|
64
|
+
const getTextInputValues = () => {
|
|
65
|
+
return new Map(textInputValues);
|
|
66
|
+
};
|
|
67
|
+
return Object.assign(interaction, {
|
|
68
|
+
reply,
|
|
69
|
+
deferReply,
|
|
70
|
+
getResponse,
|
|
71
|
+
getTextInputValue,
|
|
72
|
+
getTextInputValues,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
@@ -4,23 +4,23 @@ import type { InteractionFollowUpFlags, InteractionReplyFlags } from "../types/I
|
|
|
4
4
|
export type MessageFlagLike = MessageFlags | InteractionReplyFlags | InteractionFollowUpFlags;
|
|
5
5
|
/** Message payload accepted by helper reply/edit functions. */
|
|
6
6
|
export type InteractionMessageData = Omit<APIInteractionResponseCallbackData, "flags"> & {
|
|
7
|
-
flags?: MessageFlagLike;
|
|
7
|
+
flags?: MessageFlagLike | MessageFlagLike[];
|
|
8
8
|
};
|
|
9
9
|
/** Deferred response payload recognised by helper methods. */
|
|
10
10
|
export type DeferredResponseData = {
|
|
11
|
-
flags: MessageFlagLike;
|
|
11
|
+
flags: MessageFlagLike | MessageFlagLike[];
|
|
12
12
|
};
|
|
13
13
|
/** Options accepted when deferring a reply. */
|
|
14
14
|
export type DeferReplyOptions = {
|
|
15
|
-
flags?: MessageFlagLike;
|
|
15
|
+
flags?: MessageFlagLike | MessageFlagLike[];
|
|
16
16
|
};
|
|
17
17
|
/**
|
|
18
18
|
* Normalises helper flag enums into the raw Discord `MessageFlags` bitfield.
|
|
19
19
|
*
|
|
20
|
-
* @param flags - A flag from helper enums or raw Discord flags.
|
|
20
|
+
* @param flags - A flag or array of flags from helper enums or raw Discord flags.
|
|
21
21
|
* @returns The value coerced to a `MessageFlags` compatible bitfield.
|
|
22
22
|
*/
|
|
23
|
-
export declare function normaliseMessageFlags(flags: MessageFlagLike | undefined): MessageFlags | undefined;
|
|
23
|
+
export declare function normaliseMessageFlags(flags: MessageFlagLike | MessageFlagLike[] | undefined): MessageFlags | undefined;
|
|
24
24
|
/**
|
|
25
25
|
* Ensures helper message payloads include correctly normalised message flags.
|
|
26
26
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ComponentType, MessageFlags as RawMessageFlags } from "discord-api-types/v10";
|
|
1
|
+
import { ComponentType, MessageFlags as RawMessageFlags, } from "discord-api-types/v10";
|
|
2
2
|
const COMPONENTS_V2_TYPES = new Set([
|
|
3
3
|
ComponentType.Container,
|
|
4
4
|
ComponentType.Section,
|
|
@@ -11,11 +11,21 @@ const COMPONENTS_V2_TYPES = new Set([
|
|
|
11
11
|
/**
|
|
12
12
|
* Normalises helper flag enums into the raw Discord `MessageFlags` bitfield.
|
|
13
13
|
*
|
|
14
|
-
* @param flags - A flag from helper enums or raw Discord flags.
|
|
14
|
+
* @param flags - A flag or array of flags from helper enums or raw Discord flags.
|
|
15
15
|
* @returns The value coerced to a `MessageFlags` compatible bitfield.
|
|
16
16
|
*/
|
|
17
17
|
export function normaliseMessageFlags(flags) {
|
|
18
|
-
|
|
18
|
+
if (flags === undefined) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
if (Array.isArray(flags)) {
|
|
22
|
+
if (flags.length === 0) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
// Combine multiple flags using bitwise OR
|
|
26
|
+
return flags.reduce((acc, flag) => (acc | flag), 0);
|
|
27
|
+
}
|
|
28
|
+
return flags;
|
|
19
29
|
}
|
|
20
30
|
/**
|
|
21
31
|
* Ensures helper message payloads include correctly normalised message flags.
|
|
@@ -27,19 +37,34 @@ export function normaliseInteractionMessageData(data) {
|
|
|
27
37
|
if (!data) {
|
|
28
38
|
return undefined;
|
|
29
39
|
}
|
|
30
|
-
|
|
31
|
-
|
|
40
|
+
// Auto-convert builders to JSON
|
|
41
|
+
const normalisedComponents = data.components
|
|
42
|
+
? data.components.map((component) => resolveComponentLike(component))
|
|
43
|
+
: undefined;
|
|
44
|
+
const normalisedEmbeds = data.embeds
|
|
45
|
+
? data.embeds.map((embed) => resolveComponentLike(embed))
|
|
46
|
+
: undefined;
|
|
47
|
+
const usesComponentsV2 = Array.isArray(normalisedComponents)
|
|
48
|
+
? containsComponentsV2(normalisedComponents)
|
|
32
49
|
: false;
|
|
33
50
|
const normalisedFlags = normaliseMessageFlags(data.flags);
|
|
34
51
|
const finalFlags = usesComponentsV2
|
|
35
|
-
? ((normalisedFlags ?? 0) |
|
|
52
|
+
? ((normalisedFlags ?? 0) |
|
|
53
|
+
RawMessageFlags.IsComponentsV2)
|
|
36
54
|
: normalisedFlags;
|
|
37
|
-
|
|
55
|
+
const needsNormalisation = finalFlags !== data.flags ||
|
|
56
|
+
normalisedComponents !== data.components ||
|
|
57
|
+
normalisedEmbeds !== data.embeds;
|
|
58
|
+
if (!needsNormalisation) {
|
|
38
59
|
return data;
|
|
39
60
|
}
|
|
40
|
-
const { flags: _flags, ...rest } = data;
|
|
61
|
+
const { flags: _flags, components: _components, embeds: _embeds, ...rest } = data;
|
|
41
62
|
return {
|
|
42
63
|
...rest,
|
|
64
|
+
...(normalisedComponents !== undefined
|
|
65
|
+
? { components: normalisedComponents }
|
|
66
|
+
: {}),
|
|
67
|
+
...(normalisedEmbeds !== undefined ? { embeds: normalisedEmbeds } : {}),
|
|
43
68
|
...(finalFlags !== undefined ? { flags: finalFlags } : {}),
|
|
44
69
|
};
|
|
45
70
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@minesa-org/mini-interaction",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "Mini interaction, connecting your app with Discord via HTTP-interaction (Vercel support).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"build": "tsc --project tsconfig.json",
|
|
15
15
|
"typecheck": "tsc --noEmit",
|
|
16
16
|
"prepare": "npm run build",
|
|
17
|
+
"patch": "npm version patch",
|
|
17
18
|
"publish:npm": "npm publish",
|
|
18
19
|
"publish:gh": "npm publish --registry=https://npm.pkg.github.com"
|
|
19
20
|
},
|