@minesa-org/mini-interaction 0.1.7 → 0.1.10
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.
|
@@ -239,6 +239,12 @@ export declare class MiniInteraction {
|
|
|
239
239
|
* This is primarily used when Discord asks for a verification URL while setting up Linked Roles.
|
|
240
240
|
* Provide an HTML file that contains the `{{OAUTH_URL}}` placeholder (or a custom placeholder defined in options)
|
|
241
241
|
* and this helper will replace the token with a freshly generated OAuth link on every request.
|
|
242
|
+
*
|
|
243
|
+
* Available placeholders:
|
|
244
|
+
* - `{{OAUTH_URL}}` - HTML-escaped OAuth URL for links/buttons.
|
|
245
|
+
* - `{{OAUTH_URL_RAW}}` - raw OAuth URL, ideal for `<script>` usage.
|
|
246
|
+
* - `{{OAUTH_STATE}}` - HTML-escaped OAuth state value.
|
|
247
|
+
* - Custom placeholder name (from {@link DiscordOAuthVerificationPageOptions.placeholder}) and its `_RAW` variant.
|
|
242
248
|
*/
|
|
243
249
|
discordOAuthVerificationPage(options?: DiscordOAuthVerificationPageOptions): MiniInteractionNodeHandler;
|
|
244
250
|
/**
|
|
@@ -264,7 +270,7 @@ export declare class MiniInteraction {
|
|
|
264
270
|
private loadHtmlTemplate;
|
|
265
271
|
/**
|
|
266
272
|
* Replaces placeholder tokens in a template with escaped HTML values.
|
|
267
|
-
|
|
273
|
+
*/
|
|
268
274
|
private renderHtmlTemplate;
|
|
269
275
|
/**
|
|
270
276
|
* Normalizes placeholder tokens to the bare key the HTML renderer expects.
|
|
@@ -430,6 +430,12 @@ export class MiniInteraction {
|
|
|
430
430
|
* This is primarily used when Discord asks for a verification URL while setting up Linked Roles.
|
|
431
431
|
* Provide an HTML file that contains the `{{OAUTH_URL}}` placeholder (or a custom placeholder defined in options)
|
|
432
432
|
* and this helper will replace the token with a freshly generated OAuth link on every request.
|
|
433
|
+
*
|
|
434
|
+
* Available placeholders:
|
|
435
|
+
* - `{{OAUTH_URL}}` - HTML-escaped OAuth URL for links/buttons.
|
|
436
|
+
* - `{{OAUTH_URL_RAW}}` - raw OAuth URL, ideal for `<script>` usage.
|
|
437
|
+
* - `{{OAUTH_STATE}}` - HTML-escaped OAuth state value.
|
|
438
|
+
* - Custom placeholder name (from {@link DiscordOAuthVerificationPageOptions.placeholder}) and its `_RAW` variant.
|
|
433
439
|
*/
|
|
434
440
|
discordOAuthVerificationPage(options = {}) {
|
|
435
441
|
const scopes = options.scopes ?? ["identify", "role_connections.write"];
|
|
@@ -440,12 +446,20 @@ export class MiniInteraction {
|
|
|
440
446
|
return (_request, response) => {
|
|
441
447
|
try {
|
|
442
448
|
const { url, state } = generateOAuthUrl(oauthConfig, scopes);
|
|
443
|
-
const
|
|
449
|
+
const values = {
|
|
444
450
|
OAUTH_URL: url,
|
|
451
|
+
OAUTH_URL_RAW: url,
|
|
445
452
|
OAUTH_STATE: state,
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
453
|
+
};
|
|
454
|
+
const rawKeys = new Set(["OAUTH_URL_RAW"]);
|
|
455
|
+
if (placeholderKey !== "OAUTH_URL") {
|
|
456
|
+
values[placeholderKey] = url;
|
|
457
|
+
const rawVariant = `${placeholderKey}_RAW`;
|
|
458
|
+
values[rawVariant] = url;
|
|
459
|
+
rawKeys.add(rawVariant);
|
|
460
|
+
}
|
|
461
|
+
const html = this.renderHtmlTemplate(template, values, {
|
|
462
|
+
rawKeys,
|
|
449
463
|
});
|
|
450
464
|
sendHtml(response, html);
|
|
451
465
|
}
|
|
@@ -519,14 +533,18 @@ export class MiniInteraction {
|
|
|
519
533
|
}
|
|
520
534
|
/**
|
|
521
535
|
* Replaces placeholder tokens in a template with escaped HTML values.
|
|
522
|
-
|
|
523
|
-
renderHtmlTemplate(template, values) {
|
|
536
|
+
*/
|
|
537
|
+
renderHtmlTemplate(template, values, options) {
|
|
538
|
+
const rawKeys = options?.rawKeys instanceof Set
|
|
539
|
+
? options.rawKeys
|
|
540
|
+
: new Set(options?.rawKeys ?? []);
|
|
524
541
|
return template.replace(/\{\{\s*(\w+)\s*\}\}/g, (match, key) => {
|
|
525
542
|
const value = values[key];
|
|
526
543
|
if (value === undefined || value === null) {
|
|
527
544
|
return "";
|
|
528
545
|
}
|
|
529
|
-
|
|
546
|
+
const stringValue = String(value);
|
|
547
|
+
return rawKeys.has(key) ? stringValue : escapeHtml(stringValue);
|
|
530
548
|
});
|
|
531
549
|
}
|
|
532
550
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type APIInteractionResponse, type APIInteractionResponseChannelMessageWithSource, type APIInteractionResponseDeferredChannelMessageWithSource, type APIMessageApplicationCommandInteraction, type APIModalInteractionResponse, type APIModalInteractionResponseCallbackData, type APIUserApplicationCommandInteraction } from "discord-api-types/v10";
|
|
1
|
+
import { type APIInteractionResponse, type APIInteractionResponseChannelMessageWithSource, type APIInteractionResponseDeferredChannelMessageWithSource, type APIInteractionResponseUpdateMessage, type APIMessage, type APIMessageApplicationCommandInteraction, type APIModalInteractionResponse, type APIModalInteractionResponseCallbackData, type APIUser, type APIUserApplicationCommandInteraction } from "discord-api-types/v10";
|
|
2
2
|
import { DeferReplyOptions, InteractionMessageData } from "./interactionMessageHelpers.js";
|
|
3
3
|
/**
|
|
4
4
|
* Base helper methods for context menu interactions.
|
|
@@ -6,6 +6,8 @@ import { DeferReplyOptions, InteractionMessageData } from "./interactionMessageH
|
|
|
6
6
|
type ContextMenuInteractionHelpers = {
|
|
7
7
|
getResponse: () => APIInteractionResponse | null;
|
|
8
8
|
reply: (data: InteractionMessageData) => APIInteractionResponseChannelMessageWithSource;
|
|
9
|
+
followUp: (data: InteractionMessageData) => APIInteractionResponseChannelMessageWithSource;
|
|
10
|
+
editReply: (data?: InteractionMessageData) => APIInteractionResponseUpdateMessage;
|
|
9
11
|
deferReply: (options?: DeferReplyOptions) => APIInteractionResponseDeferredChannelMessageWithSource;
|
|
10
12
|
showModal: (data: APIModalInteractionResponseCallbackData | {
|
|
11
13
|
toJSON(): APIModalInteractionResponseCallbackData;
|
|
@@ -14,11 +16,17 @@ type ContextMenuInteractionHelpers = {
|
|
|
14
16
|
/**
|
|
15
17
|
* User context menu interaction with helper methods.
|
|
16
18
|
*/
|
|
17
|
-
export type UserContextMenuInteraction = APIUserApplicationCommandInteraction & ContextMenuInteractionHelpers
|
|
19
|
+
export type UserContextMenuInteraction = APIUserApplicationCommandInteraction & ContextMenuInteractionHelpers & {
|
|
20
|
+
/** Resolved user targeted by this user context menu command. */
|
|
21
|
+
targetUser?: APIUser;
|
|
22
|
+
};
|
|
18
23
|
/**
|
|
19
24
|
* Message context menu interaction with helper methods.
|
|
20
25
|
*/
|
|
21
|
-
export type MessageContextMenuInteraction = APIMessageApplicationCommandInteraction & ContextMenuInteractionHelpers
|
|
26
|
+
export type MessageContextMenuInteraction = APIMessageApplicationCommandInteraction & ContextMenuInteractionHelpers & {
|
|
27
|
+
/** Resolved message targeted by this message context menu command. */
|
|
28
|
+
targetMessage?: APIMessage;
|
|
29
|
+
};
|
|
22
30
|
/**
|
|
23
31
|
* Wraps a raw user context menu interaction with helper methods.
|
|
24
32
|
*
|
|
@@ -1,49 +1,63 @@
|
|
|
1
1
|
import { InteractionResponseType, } from "discord-api-types/v10";
|
|
2
2
|
import { normaliseInteractionMessageData, normaliseMessageFlags, } from "./interactionMessageHelpers.js";
|
|
3
|
-
|
|
4
|
-
* Wraps a raw user context menu interaction with helper methods.
|
|
5
|
-
*
|
|
6
|
-
* @param interaction - The raw user context menu interaction payload from Discord.
|
|
7
|
-
* @returns A helper-augmented interaction object.
|
|
8
|
-
*/
|
|
9
|
-
export function createUserContextMenuInteraction(interaction) {
|
|
3
|
+
function createContextMenuInteractionHelpers() {
|
|
10
4
|
let capturedResponse = null;
|
|
11
|
-
const
|
|
12
|
-
const normalised = normaliseInteractionMessageData(data);
|
|
13
|
-
if (!normalised) {
|
|
14
|
-
throw new Error("[MiniInteraction] Channel message responses require data to be provided.");
|
|
15
|
-
}
|
|
16
|
-
const response = {
|
|
17
|
-
type: InteractionResponseType.ChannelMessageWithSource,
|
|
18
|
-
data: normalised,
|
|
19
|
-
};
|
|
5
|
+
const captureResponse = (response) => {
|
|
20
6
|
capturedResponse = response;
|
|
21
7
|
return response;
|
|
22
8
|
};
|
|
9
|
+
function createMessageResponse(type, data) {
|
|
10
|
+
const normalised = normaliseInteractionMessageData(data);
|
|
11
|
+
if (type === InteractionResponseType.ChannelMessageWithSource) {
|
|
12
|
+
if (!normalised) {
|
|
13
|
+
throw new Error("[MiniInteraction] Channel message responses require data to be provided.");
|
|
14
|
+
}
|
|
15
|
+
return captureResponse({
|
|
16
|
+
type,
|
|
17
|
+
data: normalised,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
if (normalised) {
|
|
21
|
+
return captureResponse({ type, data: normalised });
|
|
22
|
+
}
|
|
23
|
+
return captureResponse({ type });
|
|
24
|
+
}
|
|
25
|
+
const reply = (data) => createMessageResponse(InteractionResponseType.ChannelMessageWithSource, data);
|
|
26
|
+
const followUp = (data) => createMessageResponse(InteractionResponseType.ChannelMessageWithSource, data);
|
|
27
|
+
const editReply = (data) => createMessageResponse(InteractionResponseType.UpdateMessage, data);
|
|
23
28
|
const deferReply = (options = {}) => {
|
|
24
29
|
const flags = normaliseMessageFlags(options.flags);
|
|
25
|
-
|
|
30
|
+
return captureResponse({
|
|
26
31
|
type: InteractionResponseType.DeferredChannelMessageWithSource,
|
|
27
32
|
data: flags ? { flags } : undefined,
|
|
28
|
-
};
|
|
29
|
-
capturedResponse = response;
|
|
30
|
-
return response;
|
|
33
|
+
});
|
|
31
34
|
};
|
|
32
35
|
const showModal = (data) => {
|
|
33
36
|
const modalData = typeof data === "object" && "toJSON" in data ? data.toJSON() : data;
|
|
34
|
-
|
|
37
|
+
return captureResponse({
|
|
35
38
|
type: InteractionResponseType.Modal,
|
|
36
39
|
data: modalData,
|
|
37
|
-
};
|
|
38
|
-
capturedResponse = response;
|
|
39
|
-
return response;
|
|
40
|
+
});
|
|
40
41
|
};
|
|
41
42
|
const getResponse = () => capturedResponse;
|
|
42
|
-
return
|
|
43
|
+
return {
|
|
44
|
+
getResponse,
|
|
43
45
|
reply,
|
|
46
|
+
followUp,
|
|
47
|
+
editReply,
|
|
44
48
|
deferReply,
|
|
45
49
|
showModal,
|
|
46
|
-
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Wraps a raw user context menu interaction with helper methods.
|
|
54
|
+
*
|
|
55
|
+
* @param interaction - The raw user context menu interaction payload from Discord.
|
|
56
|
+
* @returns A helper-augmented interaction object.
|
|
57
|
+
*/
|
|
58
|
+
export function createUserContextMenuInteraction(interaction) {
|
|
59
|
+
return Object.assign(interaction, createContextMenuInteractionHelpers(), {
|
|
60
|
+
targetUser: resolveTargetUser(interaction),
|
|
47
61
|
});
|
|
48
62
|
}
|
|
49
63
|
/**
|
|
@@ -53,42 +67,21 @@ export function createUserContextMenuInteraction(interaction) {
|
|
|
53
67
|
* @returns A helper-augmented interaction object.
|
|
54
68
|
*/
|
|
55
69
|
export function createMessageContextMenuInteraction(interaction) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const normalised = normaliseInteractionMessageData(data);
|
|
59
|
-
if (!normalised) {
|
|
60
|
-
throw new Error("[MiniInteraction] Channel message responses require data to be provided.");
|
|
61
|
-
}
|
|
62
|
-
const response = {
|
|
63
|
-
type: InteractionResponseType.ChannelMessageWithSource,
|
|
64
|
-
data: normalised,
|
|
65
|
-
};
|
|
66
|
-
capturedResponse = response;
|
|
67
|
-
return response;
|
|
68
|
-
};
|
|
69
|
-
const deferReply = (options = {}) => {
|
|
70
|
-
const flags = normaliseMessageFlags(options.flags);
|
|
71
|
-
const response = {
|
|
72
|
-
type: InteractionResponseType.DeferredChannelMessageWithSource,
|
|
73
|
-
data: flags ? { flags } : undefined,
|
|
74
|
-
};
|
|
75
|
-
capturedResponse = response;
|
|
76
|
-
return response;
|
|
77
|
-
};
|
|
78
|
-
const showModal = (data) => {
|
|
79
|
-
const modalData = typeof data === "object" && "toJSON" in data ? data.toJSON() : data;
|
|
80
|
-
const response = {
|
|
81
|
-
type: InteractionResponseType.Modal,
|
|
82
|
-
data: modalData,
|
|
83
|
-
};
|
|
84
|
-
capturedResponse = response;
|
|
85
|
-
return response;
|
|
86
|
-
};
|
|
87
|
-
const getResponse = () => capturedResponse;
|
|
88
|
-
return Object.assign(interaction, {
|
|
89
|
-
reply,
|
|
90
|
-
deferReply,
|
|
91
|
-
showModal,
|
|
92
|
-
getResponse,
|
|
70
|
+
return Object.assign(interaction, createContextMenuInteractionHelpers(), {
|
|
71
|
+
targetMessage: resolveTargetMessage(interaction),
|
|
93
72
|
});
|
|
94
73
|
}
|
|
74
|
+
function resolveTargetMessage(interaction) {
|
|
75
|
+
const targetId = interaction.data?.target_id;
|
|
76
|
+
if (!targetId) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
return interaction.data?.resolved?.messages?.[targetId];
|
|
80
|
+
}
|
|
81
|
+
function resolveTargetUser(interaction) {
|
|
82
|
+
const targetId = interaction.data?.target_id;
|
|
83
|
+
if (!targetId) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
return interaction.data?.resolved?.users?.[targetId];
|
|
87
|
+
}
|
package/package.json
CHANGED