@minesa-org/mini-interaction 0.1.6 → 0.1.9
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/README.md +0 -4
- package/dist/clients/MiniInteraction.d.ts +38 -11
- package/dist/clients/MiniInteraction.js +86 -20
- package/dist/index.d.ts +1 -1
- package/dist/utils/constants.d.ts +1 -15
- package/dist/utils/constants.js +1 -15
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
1
|
# Mini Interaction
|
|
2
2
|
|
|
3
3
|
Mini interaction, connecting your app with Discord via HTTP-interaction (Vercel support).
|
|
4
|
-
|
|
5
|
-
- Read the [Discord OAuth Linked Roles setup guide](docs/discord-oauth-setup.md)
|
|
6
|
-
for a step-by-step walkthrough that uses `mini.discordOAuthCallback()` and a
|
|
7
|
-
MongoDB connection configured via `MONGODB_URI`.
|
|
@@ -113,6 +113,23 @@ export type DiscordOAuthCallbackOptions = {
|
|
|
113
113
|
successRedirect?: string | ((context: DiscordOAuthAuthorizeContext) => string | null | undefined);
|
|
114
114
|
templates?: Partial<DiscordOAuthCallbackTemplates>;
|
|
115
115
|
};
|
|
116
|
+
/** Options accepted by {@link MiniInteraction.discordOAuthVerificationPage}. */
|
|
117
|
+
export type DiscordOAuthVerificationPageOptions = {
|
|
118
|
+
oauth?: OAuthConfig;
|
|
119
|
+
scopes?: string[];
|
|
120
|
+
/**
|
|
121
|
+
* Path to the HTML file to load. Relative paths resolve from {@link process.cwd}.
|
|
122
|
+
*
|
|
123
|
+
* @defaultValue "index.html"
|
|
124
|
+
*/
|
|
125
|
+
htmlFile?: string;
|
|
126
|
+
/**
|
|
127
|
+
* Placeholder token (with or without the `{{ }}` wrapper) that will be replaced with the generated OAuth URL.
|
|
128
|
+
*
|
|
129
|
+
* @defaultValue "OAUTH_URL"
|
|
130
|
+
*/
|
|
131
|
+
placeholder?: string;
|
|
132
|
+
};
|
|
116
133
|
/**
|
|
117
134
|
* Minimal interface describing a function capable of verifying Discord interaction signatures.
|
|
118
135
|
*/
|
|
@@ -123,7 +140,6 @@ type VerifyKeyFunction = (message: string | Uint8Array, signature: string, times
|
|
|
123
140
|
export declare class MiniInteraction {
|
|
124
141
|
readonly applicationId: string;
|
|
125
142
|
readonly publicKey: string;
|
|
126
|
-
private readonly baseUrl;
|
|
127
143
|
private readonly fetchImpl;
|
|
128
144
|
private readonly verifyKeyImpl;
|
|
129
145
|
private readonly commandsDirectory;
|
|
@@ -213,25 +229,32 @@ export declare class MiniInteraction {
|
|
|
213
229
|
*/
|
|
214
230
|
handleRequest(request: MiniInteractionRequest): Promise<MiniInteractionHandlerResult>;
|
|
215
231
|
/**
|
|
216
|
-
* Creates a Node.js style request handler
|
|
232
|
+
* Creates a Node.js style request handler compatible with Express, Next.js API routes,
|
|
233
|
+
* Vercel serverless functions, and any runtime that expects a `(req, res)` listener.
|
|
217
234
|
*/
|
|
218
235
|
createNodeHandler(): MiniInteractionNodeHandler;
|
|
219
236
|
/**
|
|
220
|
-
*
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
*
|
|
237
|
+
* Generates a lightweight verification handler that serves an HTML page with an embedded OAuth link.
|
|
238
|
+
*
|
|
239
|
+
* This is primarily used when Discord asks for a verification URL while setting up Linked Roles.
|
|
240
|
+
* Provide an HTML file that contains the `{{OAUTH_URL}}` placeholder (or a custom placeholder defined in options)
|
|
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.
|
|
225
248
|
*/
|
|
226
|
-
|
|
249
|
+
discordOAuthVerificationPage(options?: DiscordOAuthVerificationPageOptions): MiniInteractionNodeHandler;
|
|
227
250
|
/**
|
|
228
251
|
* Loads an HTML file and returns a success template that replaces useful placeholders.
|
|
229
252
|
*
|
|
230
253
|
* The following placeholders are available in the HTML file:
|
|
231
254
|
* - `{{username}}`, `{{discriminator}}`, `{{user_id}}`, `{{user_tag}}`
|
|
232
255
|
* - `{{access_token}}`, `{{refresh_token}}`, `{{token_type}}`, `{{scope}}`, `{{expires_at}}`
|
|
233
|
-
|
|
234
|
-
|
|
256
|
+
* - `{{state}}`
|
|
257
|
+
*/
|
|
235
258
|
connectedOAuthPage(filePath: string): DiscordOAuthCallbackTemplates["success"];
|
|
236
259
|
/**
|
|
237
260
|
* Loads an HTML file and returns an error template that can be reused for all failure cases.
|
|
@@ -247,8 +270,12 @@ export declare class MiniInteraction {
|
|
|
247
270
|
private loadHtmlTemplate;
|
|
248
271
|
/**
|
|
249
272
|
* Replaces placeholder tokens in a template with escaped HTML values.
|
|
250
|
-
|
|
273
|
+
*/
|
|
251
274
|
private renderHtmlTemplate;
|
|
275
|
+
/**
|
|
276
|
+
* Normalizes placeholder tokens to the bare key the HTML renderer expects.
|
|
277
|
+
*/
|
|
278
|
+
private normalizeTemplateKey;
|
|
252
279
|
/**
|
|
253
280
|
* Creates a minimal Discord OAuth callback handler that renders helpful HTML responses.
|
|
254
281
|
*
|
|
@@ -9,7 +9,7 @@ import { createCommandInteraction } from "../utils/CommandInteractionOptions.js"
|
|
|
9
9
|
import { createMessageComponentInteraction, } from "../utils/MessageComponentInteraction.js";
|
|
10
10
|
import { createModalSubmitInteraction, } from "../utils/ModalSubmitInteraction.js";
|
|
11
11
|
import { createUserContextMenuInteraction, createMessageContextMenuInteraction, } from "../utils/ContextMenuInteraction.js";
|
|
12
|
-
import { getOAuthTokens, getDiscordUser, } from "../oauth/DiscordOAuth.js";
|
|
12
|
+
import { generateOAuthUrl, getOAuthTokens, getDiscordUser, } from "../oauth/DiscordOAuth.js";
|
|
13
13
|
/** File extensions that are treated as loadable modules when auto-loading. */
|
|
14
14
|
const SUPPORTED_MODULE_EXTENSIONS = new Set([
|
|
15
15
|
".js",
|
|
@@ -25,7 +25,6 @@ const SUPPORTED_MODULE_EXTENSIONS = new Set([
|
|
|
25
25
|
export class MiniInteraction {
|
|
26
26
|
applicationId;
|
|
27
27
|
publicKey;
|
|
28
|
-
baseUrl;
|
|
29
28
|
fetchImpl;
|
|
30
29
|
verifyKeyImpl;
|
|
31
30
|
commandsDirectory;
|
|
@@ -54,7 +53,6 @@ export class MiniInteraction {
|
|
|
54
53
|
}
|
|
55
54
|
this.applicationId = applicationId;
|
|
56
55
|
this.publicKey = publicKey;
|
|
57
|
-
this.baseUrl = DISCORD_BASE_URL;
|
|
58
56
|
this.fetchImpl = fetchImpl;
|
|
59
57
|
this.verifyKeyImpl = verifyKeyImplementation ?? verifyKey;
|
|
60
58
|
this.commandsDirectory =
|
|
@@ -271,7 +269,7 @@ export class MiniInteraction {
|
|
|
271
269
|
if (!Array.isArray(resolvedCommands) || resolvedCommands.length === 0) {
|
|
272
270
|
throw new Error("[MiniInteraction] commands must be a non-empty array payload");
|
|
273
271
|
}
|
|
274
|
-
const url = `${
|
|
272
|
+
const url = `${DISCORD_BASE_URL}/applications/${this.applicationId}/commands`;
|
|
275
273
|
const response = await this.fetchImpl(url, {
|
|
276
274
|
method: "PUT",
|
|
277
275
|
headers: {
|
|
@@ -299,7 +297,7 @@ export class MiniInteraction {
|
|
|
299
297
|
if (!Array.isArray(metadata) || metadata.length === 0) {
|
|
300
298
|
throw new Error("[MiniInteraction] metadata must be a non-empty array payload");
|
|
301
299
|
}
|
|
302
|
-
const url = `${
|
|
300
|
+
const url = `${DISCORD_BASE_URL}/applications/${this.applicationId}/role-connections/metadata`;
|
|
303
301
|
const response = await this.fetchImpl(url, {
|
|
304
302
|
method: "PUT",
|
|
305
303
|
headers: {
|
|
@@ -372,7 +370,8 @@ export class MiniInteraction {
|
|
|
372
370
|
};
|
|
373
371
|
}
|
|
374
372
|
/**
|
|
375
|
-
* Creates a Node.js style request handler
|
|
373
|
+
* Creates a Node.js style request handler compatible with Express, Next.js API routes,
|
|
374
|
+
* Vercel serverless functions, and any runtime that expects a `(req, res)` listener.
|
|
376
375
|
*/
|
|
377
376
|
createNodeHandler() {
|
|
378
377
|
return (request, response) => {
|
|
@@ -426,16 +425,49 @@ export class MiniInteraction {
|
|
|
426
425
|
};
|
|
427
426
|
}
|
|
428
427
|
/**
|
|
429
|
-
*
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
*
|
|
428
|
+
* Generates a lightweight verification handler that serves an HTML page with an embedded OAuth link.
|
|
429
|
+
*
|
|
430
|
+
* This is primarily used when Discord asks for a verification URL while setting up Linked Roles.
|
|
431
|
+
* Provide an HTML file that contains the `{{OAUTH_URL}}` placeholder (or a custom placeholder defined in options)
|
|
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.
|
|
436
439
|
*/
|
|
437
|
-
|
|
438
|
-
|
|
440
|
+
discordOAuthVerificationPage(options = {}) {
|
|
441
|
+
const scopes = options.scopes ?? ["identify", "role_connections.write"];
|
|
442
|
+
const htmlFile = options.htmlFile ?? "index.html";
|
|
443
|
+
const placeholderKey = this.normalizeTemplateKey(options.placeholder ?? "OAUTH_URL");
|
|
444
|
+
const template = this.loadHtmlTemplate(htmlFile);
|
|
445
|
+
const oauthConfig = resolveOAuthConfig(options.oauth);
|
|
446
|
+
return (_request, response) => {
|
|
447
|
+
try {
|
|
448
|
+
const { url, state } = generateOAuthUrl(oauthConfig, scopes);
|
|
449
|
+
const values = {
|
|
450
|
+
OAUTH_URL: url,
|
|
451
|
+
OAUTH_URL_RAW: url,
|
|
452
|
+
OAUTH_STATE: state,
|
|
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,
|
|
463
|
+
});
|
|
464
|
+
sendHtml(response, html);
|
|
465
|
+
}
|
|
466
|
+
catch (error) {
|
|
467
|
+
console.error("[MiniInteraction] Failed to render OAuth verification page:", error);
|
|
468
|
+
sendHtml(response, DEFAULT_VERIFICATION_ERROR_HTML, 500);
|
|
469
|
+
}
|
|
470
|
+
};
|
|
439
471
|
}
|
|
440
472
|
/**
|
|
441
473
|
* Loads an HTML file and returns a success template that replaces useful placeholders.
|
|
@@ -443,8 +475,8 @@ export class MiniInteraction {
|
|
|
443
475
|
* The following placeholders are available in the HTML file:
|
|
444
476
|
* - `{{username}}`, `{{discriminator}}`, `{{user_id}}`, `{{user_tag}}`
|
|
445
477
|
* - `{{access_token}}`, `{{refresh_token}}`, `{{token_type}}`, `{{scope}}`, `{{expires_at}}`
|
|
446
|
-
|
|
447
|
-
|
|
478
|
+
* - `{{state}}`
|
|
479
|
+
*/
|
|
448
480
|
connectedOAuthPage(filePath) {
|
|
449
481
|
const template = this.loadHtmlTemplate(filePath);
|
|
450
482
|
return ({ user, tokens, state }) => {
|
|
@@ -501,16 +533,34 @@ export class MiniInteraction {
|
|
|
501
533
|
}
|
|
502
534
|
/**
|
|
503
535
|
* Replaces placeholder tokens in a template with escaped HTML values.
|
|
504
|
-
|
|
505
|
-
renderHtmlTemplate(template, values) {
|
|
536
|
+
*/
|
|
537
|
+
renderHtmlTemplate(template, values, options) {
|
|
538
|
+
const rawKeys = options?.rawKeys instanceof Set
|
|
539
|
+
? options.rawKeys
|
|
540
|
+
: new Set(options?.rawKeys ?? []);
|
|
506
541
|
return template.replace(/\{\{\s*(\w+)\s*\}\}/g, (match, key) => {
|
|
507
542
|
const value = values[key];
|
|
508
543
|
if (value === undefined || value === null) {
|
|
509
544
|
return "";
|
|
510
545
|
}
|
|
511
|
-
|
|
546
|
+
const stringValue = String(value);
|
|
547
|
+
return rawKeys.has(key) ? stringValue : escapeHtml(stringValue);
|
|
512
548
|
});
|
|
513
549
|
}
|
|
550
|
+
/**
|
|
551
|
+
* Normalizes placeholder tokens to the bare key the HTML renderer expects.
|
|
552
|
+
*/
|
|
553
|
+
normalizeTemplateKey(token) {
|
|
554
|
+
if (!token) {
|
|
555
|
+
return "OAUTH_URL";
|
|
556
|
+
}
|
|
557
|
+
const trimmed = token.trim();
|
|
558
|
+
const match = trimmed.match(/^\{\{\s*(\w+)\s*\}\}$/);
|
|
559
|
+
if (match) {
|
|
560
|
+
return match[1];
|
|
561
|
+
}
|
|
562
|
+
return trimmed || "OAUTH_URL";
|
|
563
|
+
}
|
|
514
564
|
/**
|
|
515
565
|
* Creates a minimal Discord OAuth callback handler that renders helpful HTML responses.
|
|
516
566
|
*
|
|
@@ -1224,6 +1274,22 @@ const DEFAULT_DISCORD_OAUTH_TEMPLATES = {
|
|
|
1224
1274
|
</body>
|
|
1225
1275
|
</html>`,
|
|
1226
1276
|
};
|
|
1277
|
+
const DEFAULT_VERIFICATION_ERROR_HTML = `<!DOCTYPE html>
|
|
1278
|
+
<html>
|
|
1279
|
+
<head>
|
|
1280
|
+
<meta charset="utf-8" />
|
|
1281
|
+
<title>Server Error</title>
|
|
1282
|
+
<style>
|
|
1283
|
+
body { font-family: Arial, sans-serif; max-width: 600px; margin: 50px auto; padding: 20px; text-align: center; }
|
|
1284
|
+
.error { color: #d32f2f; background: #ffebee; padding: 15px; border-radius: 5px; display: inline-block; }
|
|
1285
|
+
</style>
|
|
1286
|
+
</head>
|
|
1287
|
+
<body>
|
|
1288
|
+
<div class="error">
|
|
1289
|
+
<p>We were unable to load the Discord verification page. Please try again later.</p>
|
|
1290
|
+
</div>
|
|
1291
|
+
</body>
|
|
1292
|
+
</html>`;
|
|
1227
1293
|
function sendHtml(response, body, statusCode = 200) {
|
|
1228
1294
|
if (response.headersSent || response.writableEnded) {
|
|
1229
1295
|
return;
|
package/dist/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export type { AttachmentOptionBuilder, ChannelOptionBuilder, MentionableOptionBu
|
|
|
7
7
|
export { CommandInteractionOptionResolver, createCommandInteraction, } from "./utils/CommandInteractionOptions.js";
|
|
8
8
|
export type { CommandInteraction, MentionableOption, ResolvedUserOption, } from "./utils/CommandInteractionOptions.js";
|
|
9
9
|
export type { UserContextMenuInteraction, MessageContextMenuInteraction, } from "./utils/ContextMenuInteraction.js";
|
|
10
|
-
export type { MiniInteractionFetchHandler, MiniInteractionNodeHandler, MiniInteractionHandlerResult, MiniInteractionRequest, MiniInteractionOptions, DiscordOAuthAuthorizeContext, DiscordOAuthCallbackOptions, DiscordOAuthCallbackTemplates, DiscordOAuthErrorTemplateContext, DiscordOAuthServerErrorTemplateContext, DiscordOAuthStateTemplateContext, DiscordOAuthSuccessTemplateContext, } from "./clients/MiniInteraction.js";
|
|
10
|
+
export type { MiniInteractionFetchHandler, MiniInteractionNodeHandler, MiniInteractionHandlerResult, MiniInteractionRequest, MiniInteractionOptions, DiscordOAuthAuthorizeContext, DiscordOAuthCallbackOptions, DiscordOAuthCallbackTemplates, DiscordOAuthErrorTemplateContext, DiscordOAuthServerErrorTemplateContext, DiscordOAuthStateTemplateContext, DiscordOAuthSuccessTemplateContext, DiscordOAuthVerificationPageOptions, } from "./clients/MiniInteraction.js";
|
|
11
11
|
export type { MiniInteractionCommand, SlashCommandHandler, UserCommandHandler, MessageCommandHandler, CommandHandler, } from "./types/Commands.js";
|
|
12
12
|
export type { MiniInteractionComponent, MiniInteractionButtonHandler, MiniInteractionStringSelectHandler, MiniInteractionRoleSelectHandler, MiniInteractionUserSelectHandler, MiniInteractionChannelSelectHandler, MiniInteractionMentionableSelectHandler, MiniInteractionComponentHandler, MiniInteractionModal, MiniInteractionModalHandler, MiniInteractionHandler, } from "./clients/MiniInteraction.js";
|
|
13
13
|
export type { MessageComponentInteraction, ButtonInteraction, StringSelectInteraction, RoleSelectInteraction, UserSelectInteraction, ChannelSelectInteraction, MentionableSelectInteraction, ResolvedUserOption as ComponentResolvedUserOption, ResolvedMentionableOption as ComponentResolvedMentionableOption, } from "./utils/MessageComponentInteraction.js";
|
|
@@ -1,16 +1,2 @@
|
|
|
1
|
-
import "dotenv/config";
|
|
2
|
-
/** Discord application's public key used for request signature verification. */
|
|
3
|
-
declare const DISCORD_APP_PUBLIC_KEY: string;
|
|
4
|
-
/** Discord application identifier used for REST requests. */
|
|
5
|
-
declare const DISCORD_APPLICATION_ID: string;
|
|
6
|
-
/** Bot token used when registering commands against Discord's API. */
|
|
7
|
-
declare const DISCORD_BOT_TOKEN: string;
|
|
8
|
-
/** Guild identifier used for guild-scoped command registration. */
|
|
9
|
-
declare const DISCORD_GUILD_ID: string;
|
|
10
|
-
/** Whether commands should be registered globally instead of per guild. */
|
|
11
|
-
declare const DISCORD_GLOBAL: boolean;
|
|
12
|
-
/** Local development port for the example interaction server. */
|
|
13
|
-
declare const DISCORD_APP_PORT: string;
|
|
14
1
|
/** Discord REST API base URL used for all network requests. */
|
|
15
|
-
declare const DISCORD_BASE_URL
|
|
16
|
-
export { DISCORD_APPLICATION_ID, DISCORD_APP_PORT, DISCORD_APP_PUBLIC_KEY, DISCORD_BASE_URL, DISCORD_BOT_TOKEN, DISCORD_GLOBAL, DISCORD_GUILD_ID, };
|
|
2
|
+
export declare const DISCORD_BASE_URL: "https://discord.com/api/v10";
|
package/dist/utils/constants.js
CHANGED
|
@@ -1,16 +1,2 @@
|
|
|
1
|
-
import "dotenv/config";
|
|
2
|
-
/** Discord application's public key used for request signature verification. */
|
|
3
|
-
const DISCORD_APP_PUBLIC_KEY = process.env.DISCORD_APP_PUBLIC_KEY;
|
|
4
|
-
/** Discord application identifier used for REST requests. */
|
|
5
|
-
const DISCORD_APPLICATION_ID = process.env.DISCORD_APPLICATION_ID;
|
|
6
|
-
/** Bot token used when registering commands against Discord's API. */
|
|
7
|
-
const DISCORD_BOT_TOKEN = process.env.DISCORD_BOT_TOKEN;
|
|
8
|
-
/** Guild identifier used for guild-scoped command registration. */
|
|
9
|
-
const DISCORD_GUILD_ID = process.env.DISCORD_GUILD_ID;
|
|
10
|
-
/** Whether commands should be registered globally instead of per guild. */
|
|
11
|
-
const DISCORD_GLOBAL = (process.env.DISCORD_GLOBAL ?? "false").toLowerCase() === "true";
|
|
12
|
-
/** Local development port for the example interaction server. */
|
|
13
|
-
const DISCORD_APP_PORT = process.env.DISCORD_PORT;
|
|
14
1
|
/** Discord REST API base URL used for all network requests. */
|
|
15
|
-
const DISCORD_BASE_URL = "https://discord.com/api/v10";
|
|
16
|
-
export { DISCORD_APPLICATION_ID, DISCORD_APP_PORT, DISCORD_APP_PUBLIC_KEY, DISCORD_BASE_URL, DISCORD_BOT_TOKEN, DISCORD_GLOBAL, DISCORD_GUILD_ID, };
|
|
2
|
+
export const DISCORD_BASE_URL = "https://discord.com/api/v10";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@minesa-org/mini-interaction",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
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",
|
|
@@ -41,8 +41,7 @@
|
|
|
41
41
|
"homepage": "https://github.com/minesa-org/mini-interaction#readme",
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"discord-api-types": "^0.38.32",
|
|
44
|
-
"discord-interactions": "^4.4.0"
|
|
45
|
-
"dotenv": "^17.2.3"
|
|
44
|
+
"discord-interactions": "^4.4.0"
|
|
46
45
|
},
|
|
47
46
|
"devDependencies": {
|
|
48
47
|
"@types/node": "^24.10.0",
|