@minesa-org/mini-interaction 0.3.13 → 0.4.0
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 +32 -1
- package/dist/builders/FileUploadBuilder.d.ts +3 -23
- package/dist/builders/FileUploadBuilder.js +16 -53
- package/dist/builders/LabelBuilder.d.ts +3 -22
- package/dist/builders/LabelBuilder.js +16 -50
- package/dist/builders/ModalBuilder.d.ts +4 -28
- package/dist/builders/ModalBuilder.js +20 -81
- package/dist/builders/ModalChannelSelectMenuBuilder.d.ts +7 -43
- package/dist/builders/ModalChannelSelectMenuBuilder.js +22 -107
- package/dist/builders/ModalRoleSelectMenuBuilder.d.ts +6 -35
- package/dist/builders/ModalRoleSelectMenuBuilder.js +21 -90
- package/dist/builders/RadioBuilder.d.ts +17 -0
- package/dist/builders/RadioBuilder.js +29 -0
- package/dist/builders/TextInputBuilder.d.ts +3 -32
- package/dist/builders/TextInputBuilder.js +21 -83
- package/dist/builders/__tests__/builders.test.d.ts +1 -0
- package/dist/builders/__tests__/builders.test.js +31 -0
- package/dist/builders/index.d.ts +2 -0
- package/dist/builders/index.js +1 -0
- package/dist/compat/LegacyMiniInteractionAdapter.d.ts +19 -0
- package/dist/compat/LegacyMiniInteractionAdapter.js +23 -0
- package/dist/core/http/DiscordRestClient.d.ts +19 -0
- package/dist/core/http/DiscordRestClient.js +55 -0
- package/dist/core/interactions/InteractionContext.d.ts +25 -0
- package/dist/core/interactions/InteractionContext.js +44 -0
- package/dist/core/interactions/InteractionVerifier.d.ts +8 -0
- package/dist/core/interactions/InteractionVerifier.js +9 -0
- package/dist/core/interactions/__tests__/interaction-context.test.d.ts +1 -0
- package/dist/core/interactions/__tests__/interaction-context.test.js +38 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +8 -0
- package/dist/router/InteractionRouter.d.ts +12 -0
- package/dist/router/InteractionRouter.js +33 -0
- package/dist/types/discord.d.ts +11 -0
- package/dist/types/discord.js +1 -0
- package/dist/types/radio.d.ts +23 -0
- package/dist/types/radio.js +5 -0
- package/dist/types/validation.d.ts +8 -0
- package/dist/types/validation.js +26 -0
- package/package.json +55 -53
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { InteractionContext } from '../InteractionContext.js';
|
|
4
|
+
import { DiscordRestClient } from '../../http/DiscordRestClient.js';
|
|
5
|
+
function createRest() {
|
|
6
|
+
const calls = [];
|
|
7
|
+
const fetchImpl = (async (input) => {
|
|
8
|
+
calls.push(String(input));
|
|
9
|
+
return new Response(JSON.stringify({ ok: true }), { status: 200 });
|
|
10
|
+
});
|
|
11
|
+
return {
|
|
12
|
+
calls,
|
|
13
|
+
rest: new DiscordRestClient({ token: 'x', applicationId: 'app', fetchImplementation: fetchImpl }),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
const interaction = { id: '1', application_id: 'a', type: 2, token: 'tok', version: 1 };
|
|
17
|
+
test('reply/defer lifecycle', () => {
|
|
18
|
+
const { rest } = createRest();
|
|
19
|
+
const ctx = new InteractionContext({ interaction, rest });
|
|
20
|
+
const response = ctx.reply({ content: 'ok' });
|
|
21
|
+
assert.equal(response.type, 4);
|
|
22
|
+
assert.equal(ctx.hasResponded, true);
|
|
23
|
+
});
|
|
24
|
+
test('editReply and followUp call webhook endpoints', async () => {
|
|
25
|
+
const { rest, calls } = createRest();
|
|
26
|
+
const ctx = new InteractionContext({ interaction, rest });
|
|
27
|
+
await ctx.editReply({ content: 'edit' });
|
|
28
|
+
await ctx.followUp({ content: 'next' });
|
|
29
|
+
assert.equal(calls.length, 2);
|
|
30
|
+
assert.match(calls[0], /messages\/\@original/);
|
|
31
|
+
});
|
|
32
|
+
test('auto-ack diagnostics callback fires for slow handler', async () => {
|
|
33
|
+
let message = '';
|
|
34
|
+
const { rest } = createRest();
|
|
35
|
+
new InteractionContext({ interaction, rest, autoAck: { enabled: true, delayMs: 5 }, onDiagnostic: (m) => (message = m) });
|
|
36
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
37
|
+
assert.match(message, /auto-ack triggered/);
|
|
38
|
+
});
|
package/dist/index.d.ts
CHANGED
|
@@ -29,3 +29,14 @@ export { MiniDatabase } from "./database/MiniDatabase.js";
|
|
|
29
29
|
export { generateOAuthUrl, getOAuthTokens, refreshAccessToken, getDiscordUser, ensureValidToken, } from "./oauth/DiscordOAuth.js";
|
|
30
30
|
export type { OAuthConfig, OAuthTokens, DiscordUser, } from "./oauth/DiscordOAuth.js";
|
|
31
31
|
export { OAuthTokenStorage } from "./oauth/OAuthTokenStorage.js";
|
|
32
|
+
export { DiscordRestClient } from "./core/http/DiscordRestClient.js";
|
|
33
|
+
export type { DiscordRestClientOptions } from "./core/http/DiscordRestClient.js";
|
|
34
|
+
export { InteractionContext } from "./core/interactions/InteractionContext.js";
|
|
35
|
+
export type { InteractionContextOptions } from "./core/interactions/InteractionContext.js";
|
|
36
|
+
export { verifyAndParseInteraction } from "./core/interactions/InteractionVerifier.js";
|
|
37
|
+
export { InteractionRouter } from "./router/InteractionRouter.js";
|
|
38
|
+
export { LegacyMiniInteractionAdapter } from "./compat/LegacyMiniInteractionAdapter.js";
|
|
39
|
+
export type { LegacyAdapterOptions } from "./compat/LegacyMiniInteractionAdapter.js";
|
|
40
|
+
export type { APIRadioComponent, APIRadioOption } from "./types/radio.js";
|
|
41
|
+
export { RADIO_COMPONENT_TYPE } from "./types/radio.js";
|
|
42
|
+
export { ValidationError } from "./types/validation.js";
|
package/dist/index.js
CHANGED
|
@@ -20,3 +20,11 @@ export { MiniDatabaseBuilder } from "./database/MiniDatabaseBuilder.js";
|
|
|
20
20
|
export { MiniDatabase } from "./database/MiniDatabase.js";
|
|
21
21
|
export { generateOAuthUrl, getOAuthTokens, refreshAccessToken, getDiscordUser, ensureValidToken, } from "./oauth/DiscordOAuth.js";
|
|
22
22
|
export { OAuthTokenStorage } from "./oauth/OAuthTokenStorage.js";
|
|
23
|
+
// New v10 core modules
|
|
24
|
+
export { DiscordRestClient } from "./core/http/DiscordRestClient.js";
|
|
25
|
+
export { InteractionContext } from "./core/interactions/InteractionContext.js";
|
|
26
|
+
export { verifyAndParseInteraction } from "./core/interactions/InteractionVerifier.js";
|
|
27
|
+
export { InteractionRouter } from "./router/InteractionRouter.js";
|
|
28
|
+
export { LegacyMiniInteractionAdapter } from "./compat/LegacyMiniInteractionAdapter.js";
|
|
29
|
+
export { RADIO_COMPONENT_TYPE } from "./types/radio.js";
|
|
30
|
+
export { ValidationError } from "./types/validation.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { APIInteraction, APIInteractionResponse, APIMessageComponentInteraction, APIModalSubmitInteraction, APIChatInputApplicationCommandInteraction } from 'discord-api-types/v10';
|
|
2
|
+
import { InteractionContext } from '../core/interactions/InteractionContext.js';
|
|
3
|
+
export type RouterHandler<T extends APIInteraction> = (interaction: T, ctx: InteractionContext) => Promise<APIInteractionResponse | void> | APIInteractionResponse | void;
|
|
4
|
+
export declare class InteractionRouter {
|
|
5
|
+
private readonly commandHandlers;
|
|
6
|
+
private readonly componentHandlers;
|
|
7
|
+
private readonly modalHandlers;
|
|
8
|
+
onCommand(name: string, handler: RouterHandler<APIChatInputApplicationCommandInteraction>): this;
|
|
9
|
+
onComponent(customId: string, handler: RouterHandler<APIMessageComponentInteraction>): this;
|
|
10
|
+
onModal(customId: string, handler: RouterHandler<APIModalSubmitInteraction>): this;
|
|
11
|
+
dispatch(interaction: APIInteraction, ctx: InteractionContext): Promise<APIInteractionResponse | void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { InteractionType } from 'discord-api-types/v10';
|
|
2
|
+
export class InteractionRouter {
|
|
3
|
+
commandHandlers = new Map();
|
|
4
|
+
componentHandlers = new Map();
|
|
5
|
+
modalHandlers = new Map();
|
|
6
|
+
onCommand(name, handler) {
|
|
7
|
+
this.commandHandlers.set(name, handler);
|
|
8
|
+
return this;
|
|
9
|
+
}
|
|
10
|
+
onComponent(customId, handler) {
|
|
11
|
+
this.componentHandlers.set(customId, handler);
|
|
12
|
+
return this;
|
|
13
|
+
}
|
|
14
|
+
onModal(customId, handler) {
|
|
15
|
+
this.modalHandlers.set(customId, handler);
|
|
16
|
+
return this;
|
|
17
|
+
}
|
|
18
|
+
async dispatch(interaction, ctx) {
|
|
19
|
+
if (interaction.type === InteractionType.ApplicationCommand) {
|
|
20
|
+
const i = interaction;
|
|
21
|
+
return this.commandHandlers.get(i.data.name)?.(i, ctx);
|
|
22
|
+
}
|
|
23
|
+
if (interaction.type === InteractionType.MessageComponent) {
|
|
24
|
+
const i = interaction;
|
|
25
|
+
return this.componentHandlers.get(i.data.custom_id)?.(i, ctx);
|
|
26
|
+
}
|
|
27
|
+
if (interaction.type === InteractionType.ModalSubmit) {
|
|
28
|
+
const i = interaction;
|
|
29
|
+
return this.modalHandlers.get(i.data.custom_id)?.(i, ctx);
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { APIInteraction, APIInteractionResponse, APIModalInteractionResponseCallbackData, APIMessageComponent, InteractionResponseType } from 'discord-api-types/v10';
|
|
2
|
+
export type DiscordApiVersion = '10';
|
|
3
|
+
export type JsonRecord = Record<string, unknown>;
|
|
4
|
+
export type InteractionResponseLike = APIInteractionResponse | {
|
|
5
|
+
type: InteractionResponseType;
|
|
6
|
+
data?: JsonRecord;
|
|
7
|
+
};
|
|
8
|
+
export type ModalPayload = APIModalInteractionResponseCallbackData;
|
|
9
|
+
export type ComponentPayload = APIMessageComponent;
|
|
10
|
+
export type ParsedInteraction = APIInteraction;
|
|
11
|
+
export type Snowflake = string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discord API support for radio components may lag behind discord-api-types releases.
|
|
3
|
+
* These local contracts are runtime-validated and serialized as raw component payloads.
|
|
4
|
+
*/
|
|
5
|
+
export declare const RADIO_COMPONENT_TYPE: 2001;
|
|
6
|
+
export type APIRadioOption = {
|
|
7
|
+
label: string;
|
|
8
|
+
value: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
emoji?: {
|
|
11
|
+
id?: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
animated?: boolean;
|
|
14
|
+
};
|
|
15
|
+
default?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export type APIRadioComponent = {
|
|
18
|
+
type: typeof RADIO_COMPONENT_TYPE;
|
|
19
|
+
custom_id: string;
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
required?: boolean;
|
|
22
|
+
options: APIRadioOption[];
|
|
23
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare class ValidationError extends Error {
|
|
2
|
+
readonly builder: string;
|
|
3
|
+
readonly field: string;
|
|
4
|
+
constructor(builder: string, field: string, message: string);
|
|
5
|
+
}
|
|
6
|
+
export declare function assertStringLength(builder: string, field: string, value: string, min: number, max: number): void;
|
|
7
|
+
export declare function assertRange(builder: string, field: string, value: number, min: number, max: number): void;
|
|
8
|
+
export declare function assertDefined<T>(builder: string, field: string, value: T | null | undefined): T;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export class ValidationError extends Error {
|
|
2
|
+
builder;
|
|
3
|
+
field;
|
|
4
|
+
constructor(builder, field, message) {
|
|
5
|
+
super(`[${builder}] ${field}: ${message}`);
|
|
6
|
+
this.builder = builder;
|
|
7
|
+
this.field = field;
|
|
8
|
+
this.name = 'ValidationError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function assertStringLength(builder, field, value, min, max) {
|
|
12
|
+
if (value.length < min || value.length > max) {
|
|
13
|
+
throw new ValidationError(builder, field, `expected length between ${min} and ${max}, got ${value.length}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function assertRange(builder, field, value, min, max) {
|
|
17
|
+
if (!Number.isInteger(value) || value < min || value > max) {
|
|
18
|
+
throw new ValidationError(builder, field, `expected integer between ${min} and ${max}, got ${value}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function assertDefined(builder, field, value) {
|
|
22
|
+
if (value === undefined || value === null) {
|
|
23
|
+
throw new ValidationError(builder, field, 'is required');
|
|
24
|
+
}
|
|
25
|
+
return value;
|
|
26
|
+
}
|
package/package.json
CHANGED
|
@@ -1,55 +1,57 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
2
|
+
"name": "@minesa-org/mini-interaction",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Mini interaction, connecting your app with Discord via HTTP-interaction (Vercel support).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc --project tsconfig.json",
|
|
15
|
+
"postbuild": "tsx scripts/postbuild.ts",
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"prepare": "npm run build",
|
|
18
|
+
"patch": "npm version patch",
|
|
19
|
+
"publish:npm": "npm publish",
|
|
20
|
+
"publish:gh": "npm publish --registry=https://npm.pkg.github.com",
|
|
21
|
+
"test": "tsx --test src/**/*.test.ts",
|
|
22
|
+
"lint:type": "tsc --noEmit"
|
|
23
|
+
},
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/minesa-org/mini-interaction.git"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"discord",
|
|
33
|
+
"interactions",
|
|
34
|
+
"http-interaction",
|
|
35
|
+
"vercel",
|
|
36
|
+
"typescript"
|
|
37
|
+
],
|
|
38
|
+
"author": "Minesa",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/minesa-org/mini-interaction/issues"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/minesa-org/mini-interaction#readme",
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@vercel/functions": "^1.6.0",
|
|
46
|
+
"discord-api-types": "^0.38.32",
|
|
47
|
+
"discord-interactions": "^4.4.0",
|
|
48
|
+
"dotenv": "^17.2.3",
|
|
49
|
+
"mongodb": "^7.0.0"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/node": "^24.10.0",
|
|
53
|
+
"ts-node": "^10.9.2",
|
|
54
|
+
"tsx": "^4.20.6",
|
|
55
|
+
"typescript": "^5.9.3"
|
|
56
|
+
}
|
|
55
57
|
}
|