@minesa-org/mini-interaction 0.4.3 → 0.4.4
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/compat/MiniInteraction.d.ts +64 -0
- package/dist/compat/MiniInteraction.js +336 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
type TimeoutConfig = {
|
|
2
|
+
initialResponseTimeout?: number;
|
|
3
|
+
autoDeferSlowOperations?: boolean;
|
|
4
|
+
enableTimeoutWarnings?: boolean;
|
|
5
|
+
enableResponseDebugLogging?: boolean;
|
|
6
|
+
};
|
|
7
|
+
export type MiniInteractionOptions = {
|
|
8
|
+
commandsDirectory?: string;
|
|
9
|
+
componentsDirectory?: string;
|
|
10
|
+
utilsDirectory?: string;
|
|
11
|
+
timeoutConfig?: TimeoutConfig;
|
|
12
|
+
debug?: boolean;
|
|
13
|
+
cwd?: string;
|
|
14
|
+
publicKey?: string;
|
|
15
|
+
applicationId?: string;
|
|
16
|
+
token?: string;
|
|
17
|
+
};
|
|
18
|
+
type NodeRequest = {
|
|
19
|
+
body?: unknown;
|
|
20
|
+
rawBody?: string | Uint8Array | Buffer;
|
|
21
|
+
headers: Record<string, string | string[] | undefined> | {
|
|
22
|
+
get(name: string): string | null;
|
|
23
|
+
};
|
|
24
|
+
method?: string;
|
|
25
|
+
[Symbol.asyncIterator]?: () => AsyncIterableIterator<Uint8Array>;
|
|
26
|
+
on?: (event: string, listener: (...args: unknown[]) => void) => void;
|
|
27
|
+
};
|
|
28
|
+
type NodeResponse = {
|
|
29
|
+
statusCode?: number;
|
|
30
|
+
setHeader?: (name: string, value: string) => void;
|
|
31
|
+
end: (body?: string) => void;
|
|
32
|
+
status?: (code: number) => NodeResponse;
|
|
33
|
+
json?: (body: unknown) => void;
|
|
34
|
+
};
|
|
35
|
+
export declare class MiniInteraction {
|
|
36
|
+
private readonly options;
|
|
37
|
+
private readonly projectRoot;
|
|
38
|
+
private readonly rest;
|
|
39
|
+
private readonly responseStates;
|
|
40
|
+
private loadedModulesPromise?;
|
|
41
|
+
constructor(options?: MiniInteractionOptions);
|
|
42
|
+
createNodeHandler(): (req: NodeRequest, res: NodeResponse) => Promise<void>;
|
|
43
|
+
private dispatch;
|
|
44
|
+
private executeCommandHandler;
|
|
45
|
+
private executeComponentHandler;
|
|
46
|
+
private executeModalHandler;
|
|
47
|
+
private runWithResponseLifecycle;
|
|
48
|
+
private loadModules;
|
|
49
|
+
private discoverModules;
|
|
50
|
+
private loadDirectory;
|
|
51
|
+
private normalizeModuleExports;
|
|
52
|
+
private normalizeExportValue;
|
|
53
|
+
private walkFiles;
|
|
54
|
+
private isImportableModule;
|
|
55
|
+
private isInteractionCommand;
|
|
56
|
+
private getCommandName;
|
|
57
|
+
private isCustomIdHandler;
|
|
58
|
+
private looksLikeModalFile;
|
|
59
|
+
private readRawBody;
|
|
60
|
+
private getHeader;
|
|
61
|
+
private sendJson;
|
|
62
|
+
}
|
|
63
|
+
export declare const LegacyMiniInteractionAdapter: typeof MiniInteraction;
|
|
64
|
+
export {};
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import { readdir } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { ApplicationCommandType, InteractionResponseType, InteractionType, } from "discord-api-types/v10";
|
|
5
|
+
import { createCommandInteraction } from "../utils/CommandInteractionOptions.js";
|
|
6
|
+
import { createAppCommandInteraction, createMessageContextMenuInteraction, createUserContextMenuInteraction, } from "../utils/ContextMenuInteraction.js";
|
|
7
|
+
import { createMessageComponentInteraction } from "../utils/MessageComponentInteraction.js";
|
|
8
|
+
import { createModalSubmitInteraction } from "../utils/ModalSubmitInteraction.js";
|
|
9
|
+
import { DiscordRestClient } from "../core/http/DiscordRestClient.js";
|
|
10
|
+
import { verifyAndParseInteraction } from "../core/interactions/InteractionVerifier.js";
|
|
11
|
+
export class MiniInteraction {
|
|
12
|
+
options;
|
|
13
|
+
projectRoot;
|
|
14
|
+
rest;
|
|
15
|
+
responseStates = new Map();
|
|
16
|
+
loadedModulesPromise;
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
this.options = options;
|
|
19
|
+
this.projectRoot = path.resolve(options.cwd ?? process.cwd());
|
|
20
|
+
const applicationId = options.applicationId ??
|
|
21
|
+
process.env.DISCORD_APPLICATION_ID ??
|
|
22
|
+
process.env.DISCORD_APP_ID;
|
|
23
|
+
const token = options.token ??
|
|
24
|
+
process.env.DISCORD_BOT_TOKEN ??
|
|
25
|
+
process.env.DISCORD_TOKEN;
|
|
26
|
+
if (!applicationId || !token) {
|
|
27
|
+
throw new Error("[MiniInteraction] Missing Discord REST credentials. Set applicationId/token or DISCORD_APPLICATION_ID + DISCORD_BOT_TOKEN.");
|
|
28
|
+
}
|
|
29
|
+
this.rest = new DiscordRestClient({ applicationId, token });
|
|
30
|
+
}
|
|
31
|
+
createNodeHandler() {
|
|
32
|
+
return async (req, res) => {
|
|
33
|
+
try {
|
|
34
|
+
const body = await this.readRawBody(req);
|
|
35
|
+
const signature = this.getHeader(req.headers, "x-signature-ed25519");
|
|
36
|
+
const timestamp = this.getHeader(req.headers, "x-signature-timestamp");
|
|
37
|
+
const publicKey = this.options.publicKey ?? process.env.DISCORD_PUBLIC_KEY;
|
|
38
|
+
if (!publicKey) {
|
|
39
|
+
this.sendJson(res, 500, {
|
|
40
|
+
error: "[MiniInteraction] Missing DISCORD_PUBLIC_KEY.",
|
|
41
|
+
});
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (!signature || !timestamp) {
|
|
45
|
+
this.sendJson(res, 401, {
|
|
46
|
+
error: "[MiniInteraction] Missing Discord signature headers.",
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const interaction = await verifyAndParseInteraction({
|
|
51
|
+
body,
|
|
52
|
+
signature,
|
|
53
|
+
timestamp,
|
|
54
|
+
publicKey,
|
|
55
|
+
});
|
|
56
|
+
if (interaction.type === InteractionType.Ping) {
|
|
57
|
+
this.sendJson(res, 200, { type: InteractionResponseType.Pong });
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const response = await this.dispatch(interaction);
|
|
61
|
+
this.sendJson(res, 200, response ?? {
|
|
62
|
+
type: InteractionResponseType.DeferredChannelMessageWithSource,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
const message = error instanceof Error ? error.message : "[MiniInteraction] Unknown error";
|
|
67
|
+
if (this.options.debug) {
|
|
68
|
+
console.error("[MiniInteraction] createNodeHandler failed", error);
|
|
69
|
+
}
|
|
70
|
+
this.sendJson(res, 500, { error: message });
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async dispatch(interaction) {
|
|
75
|
+
const modules = await this.loadModules();
|
|
76
|
+
if (interaction.type === InteractionType.ApplicationCommand) {
|
|
77
|
+
const command = modules.commands.find((candidate) => this.getCommandName(candidate) === interaction.data.name);
|
|
78
|
+
if (!command)
|
|
79
|
+
return undefined;
|
|
80
|
+
return this.executeCommandHandler(command.handler, interaction);
|
|
81
|
+
}
|
|
82
|
+
if (interaction.type === InteractionType.MessageComponent) {
|
|
83
|
+
const component = modules.components.find((candidate) => candidate.customId === interaction.data.custom_id);
|
|
84
|
+
if (!component)
|
|
85
|
+
return undefined;
|
|
86
|
+
return this.executeComponentHandler(component.handler, interaction);
|
|
87
|
+
}
|
|
88
|
+
if (interaction.type === InteractionType.ModalSubmit) {
|
|
89
|
+
const modal = modules.modals.find((candidate) => candidate.customId === interaction.data.custom_id);
|
|
90
|
+
if (!modal)
|
|
91
|
+
return undefined;
|
|
92
|
+
return this.executeModalHandler(modal.handler, interaction);
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
async executeCommandHandler(handler, interaction) {
|
|
97
|
+
return this.runWithResponseLifecycle(interaction, async (helpers) => {
|
|
98
|
+
switch (interaction.data.type) {
|
|
99
|
+
case ApplicationCommandType.ChatInput:
|
|
100
|
+
return handler(createCommandInteraction(interaction, helpers));
|
|
101
|
+
case ApplicationCommandType.User:
|
|
102
|
+
return handler(createUserContextMenuInteraction(interaction, helpers));
|
|
103
|
+
case ApplicationCommandType.Message:
|
|
104
|
+
return handler(createMessageContextMenuInteraction(interaction, helpers));
|
|
105
|
+
default:
|
|
106
|
+
if (interaction.data.type === ApplicationCommandType.PrimaryEntryPoint) {
|
|
107
|
+
return handler(createAppCommandInteraction(interaction, helpers));
|
|
108
|
+
}
|
|
109
|
+
throw new Error(`[MiniInteraction] Unsupported application command type: ${String(interaction.data.type)}`);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
async executeComponentHandler(handler, interaction) {
|
|
114
|
+
return this.runWithResponseLifecycle(interaction, async (helpers) => handler(createMessageComponentInteraction(interaction, helpers)));
|
|
115
|
+
}
|
|
116
|
+
async executeModalHandler(handler, interaction) {
|
|
117
|
+
return this.runWithResponseLifecycle(interaction, async (helpers) => handler(createModalSubmitInteraction(interaction, helpers)));
|
|
118
|
+
}
|
|
119
|
+
async runWithResponseLifecycle(interaction, executor) {
|
|
120
|
+
let ackResponse;
|
|
121
|
+
const helpers = {
|
|
122
|
+
canRespond: (interactionId) => (this.responseStates.get(interactionId) ?? "pending") === "pending",
|
|
123
|
+
trackResponse: (interactionId, _token, state) => {
|
|
124
|
+
this.responseStates.set(interactionId, state);
|
|
125
|
+
},
|
|
126
|
+
onAck: (response) => {
|
|
127
|
+
ackResponse = response;
|
|
128
|
+
},
|
|
129
|
+
sendFollowUp: async (token, response, messageId) => {
|
|
130
|
+
const responseData = "data" in response ? response.data ?? {} : {};
|
|
131
|
+
if (messageId === "@original") {
|
|
132
|
+
await this.rest.editOriginal(token, responseData);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
await this.rest.createFollowup(token, responseData);
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
const autoDeferMs = Math.min(2500, this.options.timeoutConfig?.initialResponseTimeout ?? 2500);
|
|
139
|
+
const autoDeferTimer = this.options.timeoutConfig?.autoDeferSlowOperations === true
|
|
140
|
+
? setTimeout(() => {
|
|
141
|
+
if (!helpers.canRespond(interaction.id))
|
|
142
|
+
return;
|
|
143
|
+
if (this.options.debug || this.options.timeoutConfig?.enableResponseDebugLogging) {
|
|
144
|
+
console.warn(`[MiniInteraction] Auto-deferred interaction ${interaction.id} after ${autoDeferMs}ms.`);
|
|
145
|
+
}
|
|
146
|
+
ackResponse = {
|
|
147
|
+
type: InteractionResponseType.DeferredChannelMessageWithSource,
|
|
148
|
+
};
|
|
149
|
+
helpers.trackResponse(interaction.id, interaction.token, "deferred");
|
|
150
|
+
}, autoDeferMs)
|
|
151
|
+
: undefined;
|
|
152
|
+
const timeoutWarningMs = this.options.timeoutConfig?.initialResponseTimeout;
|
|
153
|
+
const timeoutWarningTimer = this.options.timeoutConfig?.enableTimeoutWarnings && timeoutWarningMs
|
|
154
|
+
? setTimeout(() => {
|
|
155
|
+
if (this.responseStates.get(interaction.id))
|
|
156
|
+
return;
|
|
157
|
+
console.warn(`[MiniInteraction] Interaction ${interaction.id} exceeded ${timeoutWarningMs}ms without a response.`);
|
|
158
|
+
}, timeoutWarningMs)
|
|
159
|
+
: undefined;
|
|
160
|
+
try {
|
|
161
|
+
const result = await executor(helpers);
|
|
162
|
+
if (this.options.debug || this.options.timeoutConfig?.enableResponseDebugLogging) {
|
|
163
|
+
console.debug(`[MiniInteraction] Interaction ${interaction.id} completed with ${result ? "explicit" : "fallback"} response.`);
|
|
164
|
+
}
|
|
165
|
+
return result ?? ackResponse;
|
|
166
|
+
}
|
|
167
|
+
finally {
|
|
168
|
+
if (autoDeferTimer)
|
|
169
|
+
clearTimeout(autoDeferTimer);
|
|
170
|
+
if (timeoutWarningTimer)
|
|
171
|
+
clearTimeout(timeoutWarningTimer);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
async loadModules() {
|
|
175
|
+
if (!this.loadedModulesPromise) {
|
|
176
|
+
this.loadedModulesPromise = this.discoverModules();
|
|
177
|
+
}
|
|
178
|
+
return this.loadedModulesPromise;
|
|
179
|
+
}
|
|
180
|
+
async discoverModules() {
|
|
181
|
+
const commands = this.options.commandsDirectory
|
|
182
|
+
? await this.loadDirectory(this.options.commandsDirectory)
|
|
183
|
+
: [];
|
|
184
|
+
const components = this.options.componentsDirectory
|
|
185
|
+
? await this.loadDirectory(this.options.componentsDirectory)
|
|
186
|
+
: [];
|
|
187
|
+
const loaded = {
|
|
188
|
+
commands: [],
|
|
189
|
+
components: [],
|
|
190
|
+
modals: [],
|
|
191
|
+
};
|
|
192
|
+
for (const { filePath, value } of commands) {
|
|
193
|
+
if (this.isInteractionCommand(value)) {
|
|
194
|
+
loaded.commands.push(value);
|
|
195
|
+
}
|
|
196
|
+
else if (this.options.debug) {
|
|
197
|
+
console.warn(`[MiniInteraction] Ignored non-command module: ${filePath}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
for (const { filePath, value } of components) {
|
|
201
|
+
if (!this.isCustomIdHandler(value)) {
|
|
202
|
+
if (this.options.debug) {
|
|
203
|
+
console.warn(`[MiniInteraction] Ignored non-component module: ${filePath}`);
|
|
204
|
+
}
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (this.looksLikeModalFile(filePath)) {
|
|
208
|
+
loaded.modals.push(value);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
loaded.components.push(value);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return loaded;
|
|
215
|
+
}
|
|
216
|
+
async loadDirectory(directory) {
|
|
217
|
+
const absoluteDirectory = path.resolve(this.projectRoot, directory);
|
|
218
|
+
const files = await this.walkFiles(absoluteDirectory);
|
|
219
|
+
const loaded = await Promise.all(files
|
|
220
|
+
.filter((filePath) => this.isImportableModule(filePath))
|
|
221
|
+
.map(async (filePath) => ({
|
|
222
|
+
filePath,
|
|
223
|
+
values: this.normalizeModuleExports(await import(pathToFileURL(filePath).href)),
|
|
224
|
+
})));
|
|
225
|
+
return loaded.flatMap(({ filePath, values }) => values.map((value) => ({ filePath, value })));
|
|
226
|
+
}
|
|
227
|
+
normalizeModuleExports(moduleValue) {
|
|
228
|
+
const values = [];
|
|
229
|
+
if ("default" in moduleValue) {
|
|
230
|
+
values.push(...this.normalizeExportValue(moduleValue.default));
|
|
231
|
+
}
|
|
232
|
+
for (const [key, value] of Object.entries(moduleValue)) {
|
|
233
|
+
if (key === "default")
|
|
234
|
+
continue;
|
|
235
|
+
values.push(...this.normalizeExportValue(value));
|
|
236
|
+
}
|
|
237
|
+
return values;
|
|
238
|
+
}
|
|
239
|
+
normalizeExportValue(value) {
|
|
240
|
+
if (Array.isArray(value))
|
|
241
|
+
return value;
|
|
242
|
+
return [value];
|
|
243
|
+
}
|
|
244
|
+
async walkFiles(directory) {
|
|
245
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
246
|
+
const results = await Promise.all(entries.map(async (entry) => {
|
|
247
|
+
const resolvedPath = path.join(directory, entry.name);
|
|
248
|
+
if (entry.isDirectory()) {
|
|
249
|
+
return this.walkFiles(resolvedPath);
|
|
250
|
+
}
|
|
251
|
+
return [resolvedPath];
|
|
252
|
+
}));
|
|
253
|
+
return results.flat();
|
|
254
|
+
}
|
|
255
|
+
isImportableModule(filePath) {
|
|
256
|
+
if (filePath.endsWith(".d.ts"))
|
|
257
|
+
return false;
|
|
258
|
+
return /\.(ts|mts|js|mjs|cjs)$/i.test(filePath);
|
|
259
|
+
}
|
|
260
|
+
isInteractionCommand(value) {
|
|
261
|
+
return (typeof value === "object" &&
|
|
262
|
+
value !== null &&
|
|
263
|
+
"data" in value &&
|
|
264
|
+
"handler" in value &&
|
|
265
|
+
typeof value.handler === "function");
|
|
266
|
+
}
|
|
267
|
+
getCommandName(command) {
|
|
268
|
+
const data = command.data;
|
|
269
|
+
if (typeof data.toJSON === "function") {
|
|
270
|
+
return data.toJSON().name;
|
|
271
|
+
}
|
|
272
|
+
return data.name;
|
|
273
|
+
}
|
|
274
|
+
isCustomIdHandler(value) {
|
|
275
|
+
return (typeof value === "object" &&
|
|
276
|
+
value !== null &&
|
|
277
|
+
"customId" in value &&
|
|
278
|
+
"handler" in value &&
|
|
279
|
+
typeof value.customId === "string" &&
|
|
280
|
+
typeof value.handler === "function");
|
|
281
|
+
}
|
|
282
|
+
looksLikeModalFile(filePath) {
|
|
283
|
+
const normalized = filePath.toLowerCase();
|
|
284
|
+
return (normalized.includes(`${path.sep}modals${path.sep}`) ||
|
|
285
|
+
normalized.endsWith(".modal.ts") ||
|
|
286
|
+
normalized.endsWith(".modal.js") ||
|
|
287
|
+
normalized.includes("_modal.") ||
|
|
288
|
+
normalized.includes("-modal."));
|
|
289
|
+
}
|
|
290
|
+
async readRawBody(req) {
|
|
291
|
+
if (typeof req.rawBody === "string")
|
|
292
|
+
return req.rawBody;
|
|
293
|
+
if (req.rawBody instanceof Uint8Array) {
|
|
294
|
+
return Buffer.from(req.rawBody).toString("utf8");
|
|
295
|
+
}
|
|
296
|
+
if (typeof req.body === "string")
|
|
297
|
+
return req.body;
|
|
298
|
+
if (req.body instanceof Uint8Array) {
|
|
299
|
+
return Buffer.from(req.body).toString("utf8");
|
|
300
|
+
}
|
|
301
|
+
if (req.body && typeof req.body === "object") {
|
|
302
|
+
return JSON.stringify(req.body);
|
|
303
|
+
}
|
|
304
|
+
if (typeof req[Symbol.asyncIterator] === "function") {
|
|
305
|
+
const chunks = [];
|
|
306
|
+
for await (const chunk of req) {
|
|
307
|
+
chunks.push(Buffer.from(chunk));
|
|
308
|
+
}
|
|
309
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
310
|
+
}
|
|
311
|
+
return "";
|
|
312
|
+
}
|
|
313
|
+
getHeader(headers, name) {
|
|
314
|
+
if (typeof headers.get === "function") {
|
|
315
|
+
return headers.get(name) ?? undefined;
|
|
316
|
+
}
|
|
317
|
+
const recordHeaders = headers;
|
|
318
|
+
const direct = recordHeaders[name] ??
|
|
319
|
+
recordHeaders[name.toLowerCase()] ??
|
|
320
|
+
recordHeaders[name.toUpperCase()];
|
|
321
|
+
if (Array.isArray(direct))
|
|
322
|
+
return direct[0];
|
|
323
|
+
return direct;
|
|
324
|
+
}
|
|
325
|
+
sendJson(res, statusCode, body) {
|
|
326
|
+
if (typeof res.status === "function" && typeof res.json === "function") {
|
|
327
|
+
const response = res.status(statusCode);
|
|
328
|
+
response.json?.(body);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
res.statusCode = statusCode;
|
|
332
|
+
res.setHeader?.("Content-Type", "application/json; charset=utf-8");
|
|
333
|
+
res.end(JSON.stringify(body));
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
export const LegacyMiniInteractionAdapter = MiniInteraction;
|
package/dist/index.d.ts
CHANGED
|
@@ -30,6 +30,8 @@ export { InteractionContext } from "./core/interactions/InteractionContext.js";
|
|
|
30
30
|
export type { InteractionContextOptions } from "./core/interactions/InteractionContext.js";
|
|
31
31
|
export { verifyAndParseInteraction } from "./core/interactions/InteractionVerifier.js";
|
|
32
32
|
export { InteractionRouter } from "./router/InteractionRouter.js";
|
|
33
|
+
export { MiniInteraction, LegacyMiniInteractionAdapter, } from "./compat/MiniInteraction.js";
|
|
34
|
+
export type { MiniInteractionOptions } from "./compat/MiniInteraction.js";
|
|
33
35
|
export type { APIRadioComponent, APIRadioOption } from "./types/radio.js";
|
|
34
36
|
export { RADIO_COMPONENT_TYPE } from "./types/radio.js";
|
|
35
37
|
export type { APICheckboxComponent, APICheckboxOption } from "./types/checkbox.js";
|
package/dist/index.js
CHANGED
|
@@ -23,6 +23,7 @@ export { DiscordRestClient } from "./core/http/DiscordRestClient.js";
|
|
|
23
23
|
export { InteractionContext } from "./core/interactions/InteractionContext.js";
|
|
24
24
|
export { verifyAndParseInteraction } from "./core/interactions/InteractionVerifier.js";
|
|
25
25
|
export { InteractionRouter } from "./router/InteractionRouter.js";
|
|
26
|
+
export { MiniInteraction, LegacyMiniInteractionAdapter, } from "./compat/MiniInteraction.js";
|
|
26
27
|
export { RADIO_COMPONENT_TYPE } from "./types/radio.js";
|
|
27
28
|
export { CHECKBOX_COMPONENT_TYPE } from "./types/checkbox.js";
|
|
28
29
|
export { ValidationError } from "./types/validation.js";
|
package/package.json
CHANGED