UNPKG

dressed

Version:

A sleek, serverless-ready Discord bot framework.

154 lines 6.11 kB
import ora from "ora"; import { verifySignature } from "./signature.js"; import { ApplicationWebhookType, InteractionType, } from "discord-api-types/v10"; import { createServer as createHttpServer } from "node:http"; import { stdout } from "node:process"; import { Buffer } from "node:buffer"; import { createInteraction } from "./extenders/interaction.js"; import { setupCommands } from "./handlers/commands.js"; import { setupComponents } from "./handlers/components.js"; import { setupEvents } from "./handlers/events.js"; /** * Starts a server to handle interactions. * @returns The server instance */ export function createServer(commands, components, events, config) { var _a; const server = createHttpServer((req, res) => { var _a; if (req.url !== ((_a = config.endpoint) !== null && _a !== void 0 ? _a : "/")) { res.statusCode = 404; res.end(); return; } else if (req.method !== "POST") { res.statusCode = 405; res.end(); return; } const chunks = []; req .on("data", (c) => chunks.push(c)) .on("end", async () => { const handlerRes = await handleRequest(new Request("http://localhost", { method: "POST", body: Buffer.concat(chunks), headers: req.headers, }), commands, components, events, config); res.statusCode = handlerRes.status; res.setHeader("Content-Type", "application/json"); res.end(handlerRes.status === 200 ? '{"type":1}' : null); }); }); const port = (_a = config.port) !== null && _a !== void 0 ? _a : 8000; server.listen(port, "0.0.0.0", () => { var _a; console.log("Bot is now listening on", new URL((_a = config.endpoint) !== null && _a !== void 0 ? _a : "", `http://localhost:${port}`).href); }); function shutdown() { server.close(() => process.exit(0)); } process.on("SIGTERM", shutdown); process.on("SIGINT", shutdown); return server; } /** * Handles a request from Discord. * @param req The request from Discord * @param commands A list of commands or the function to run a command * @param components A list of components or the function to run a component * @param events A list of events or the function to run an event * @param config Configuration for your server * @returns The response to send back to Discord */ export async function handleRequest(req, commands, components, events, config) { const reqLoader = ora({ stream: stdout, text: "Validating new request", }).start(); const body = await req.text(); if (!verifySignature(body, req.headers.get("x-signature-ed25519"), req.headers.get("x-signature-timestamp"))) { reqLoader.fail("Invalid signature"); return new Response(null, { status: 401 }); } reqLoader.stop(); try { const json = JSON.parse(body); let status = 500; // The interaction response token if ("token" in json) { status = handleInteraction(commands, components, json, config === null || config === void 0 ? void 0 : config.middleware); } else { status = handleEvent(events, json, config === null || config === void 0 ? void 0 : config.middleware); } return new Response(status === 200 ? '{"type":1}' : null, { status, }); } catch (error) { console.error("Failed to process request:", error); return new Response(null, { status: 500 }); } } /** * Runs an interaction, takes functions to run commands/components/middleware and the request body */ export function handleInteraction(commands, components, json, middleware) { switch (json.type) { case InteractionType.Ping: { console.log("Received ping test"); return 200; } case InteractionType.ApplicationCommand: { const command = json; const interaction = createInteraction(command); const runCommand = typeof commands === "function" ? commands : setupCommands(commands); runCommand(interaction, middleware === null || middleware === void 0 ? void 0 : middleware.commands); return 202; } case InteractionType.ApplicationCommandAutocomplete: { const autocomplete = json; const interaction = createInteraction(autocomplete); const runCommand = typeof commands === "function" ? commands : setupCommands(commands); runCommand(interaction, undefined, "autocomplete"); return 202; } case InteractionType.MessageComponent: case InteractionType.ModalSubmit: { const component = json; const interaction = createInteraction(component); const runComponent = typeof components === "function" ? components : setupComponents(components); runComponent(interaction, middleware === null || middleware === void 0 ? void 0 : middleware.components); return 202; } default: { console.error("Received unknown interaction type:", json.type); return 404; } } } /** * Runs an event, takes a function to run events/middleware and the request body */ export function handleEvent(events, json, middleware) { switch (json.type) { case ApplicationWebhookType.Ping: { console.log("Received ping test"); return 200; } case ApplicationWebhookType.Event: { const event = json.event; const runEvent = typeof events === "function" ? events : setupEvents(events); runEvent(event, middleware === null || middleware === void 0 ? void 0 : middleware.events); return 202; } default: { console.log("Received unknown event type:", json.type); return 404; } } } //# sourceMappingURL=server.js.map