UNPKG

botpanel.js

Version:

A simple library for integrating Discord bots with Bot Panel

292 lines (291 loc) 13.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DashboardChangeInteraction = exports.DashboardRequestInteraction = exports.DashboardInteraction = exports.Client = void 0; const Common = __importStar(require("./common")); const ws_1 = __importDefault(require("ws")); const node_events_1 = __importDefault(require("node:events")); /*eslint-disable */ // ts wont shut up if I put any type other than "any" for this or the messageHandlers. maybe theres a way to fix this, but I don't know it. function getEnumKeyByEnumValue(myEnum, enumValue) { const keys = Object.keys(myEnum).filter(x => myEnum[x] == enumValue); return keys.length > 0 ? keys[0] : null; } const messageHandlers = { /*eslint-enable */ [Common.OperationCodes.AUTHENTICATE]: (client) => { var _a, _b, _c; (_a = client.ws) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify({ op: Common.OperationCodes.AUTHENTICATE, d: { connectAs: (_b = client.authOptions.connectAs) !== null && _b !== void 0 ? _b : 'application', applicationId: client.authOptions.id, applicationSecret: client.authOptions.secret, version: (_c = client.authOptions.wssVersionOverride) !== null && _c !== void 0 ? _c : Common.BP_VERSION } })); }, [Common.OperationCodes.AUTH_SUCCESS]: (client, data, debugOptions) => { client.connected = true; client.emit('debug', `Successfully authenticated with application "${data.name}" (${client.authOptions.id})`); if (debugOptions === null || debugOptions === void 0 ? void 0 : debugOptions.logHeartbeat) client.emit('debug', 'Heartbeat interval set to ' + data.heartbeatInterval); client.heartbeatInterval = setInterval(() => { var _a; (_a = client.ws) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify({ op: Common.OperationCodes.HEARTBEAT })); if (debugOptions === null || debugOptions === void 0 ? void 0 : debugOptions.logHeartbeat) client.emit('debug', 'Heartbeat sent'); }, data.heartbeatInterval); return data; }, [Common.OperationCodes.ERROR]: (client, data) => { if (!client.connected) client.emit('debug', 'Failed to authenticate'); let error = data.error; if (error.toLowerCase().includes('invalid websocket version')) error = 'Outdated WebSocket server version. Please update BotPanel.js.'; throw Error(error); }, [Common.OperationCodes.GUILD_INTERACTION]: (client, data) => { return new DashboardRequestInteraction(client, { interactionId: data.interactionId, guildId: data.guildId, include: data.include }); }, [Common.OperationCodes.MODIFY_GUILD_DATA]: (client, data) => { return new DashboardChangeInteraction(client, data); } }; /** * Represents a client for Bot Panel * @constructor */ class Client extends node_events_1.default { /** * @param options Authentication options */ constructor(options, debugOptions) { super(); /** Whether the client is currently connected to the WebSocket */ this.connected = false; this.authOptions = options; this.debugOptions = debugOptions; } /** Connects to the Bot Panel WebSocket and login */ login() { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve) => { var _a; try { const ws = new ws_1.default((_a = this.authOptions.wss) !== null && _a !== void 0 ? _a : 'wss://wss.botpanel.xyz'); if (this.ws) this.ws.close; this.ws = ws; this.connected = false; ws.onopen = () => { this.emit('debug', 'Connection initialized.'); resolve(ws); }; ws.onclose = (event) => { var _a; clearInterval(this.heartbeatInterval); this.connected = false; this.emit('debug', 'Connection closed.'); this.emit('close'); if (event.code != 1005 && !((_a = this.debugOptions) === null || _a === void 0 ? void 0 : _a.disableAutoReconnect)) { this.emit('debug', 'Reconnecting to WebSocket in 5 seconds.'); setTimeout(() => { this.login(); }, 5000); } }; ws.on('error', (err) => { console.error('WebSocket', err); ws.close(); }); ws.onmessage = (event) => { var _a; const message = event.data.toString(); const data = JSON.parse(message); this.emit('message', message); let dataToSend; const eventHandler = messageHandlers[data.op]; if (!eventHandler) return; try { dataToSend = eventHandler(this, data.d, this.debugOptions); } catch (err) { this.emit('debug', `[${Common.OperationCodes[data.op]}]: ${err}`); throw err; } this.emit((_a = getEnumKeyByEnumValue(Common.OperationCodes, data.op)) !== null && _a !== void 0 ? _a : data.op.toString(), dataToSend); }; } catch (err) { this.emit('debug', 'Failed to connect: ' + err); throw err; } }); }); } /** Closes the WebSocket connection */ disconnect() { var _a; if (this.connected) (_a = this.ws) === null || _a === void 0 ? void 0 : _a.close(); } /** Sends a message to the WebSocket server (as JSON) */ send(message) { var _a; (_a = this.ws) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify(message)); } } exports.Client = Client; class DashboardInteraction { constructor(client, options) { this.client = client; this.id = options.interactionId; this.guildId = options.guildId; } } exports.DashboardInteraction = DashboardInteraction; /** * Guild information request interaction */ class DashboardRequestInteraction extends DashboardInteraction { constructor(client, options) { super(client, options); this.requestedElements = options.include; } /** * Sends an interaction response containing guild information * @param data Guild info */ send(info) { var _a, _b, _c; return __awaiter(this, void 0, void 0, function* () { (_a = info.data) !== null && _a !== void 0 ? _a : (info.data = {}); // convert array values into strings for (const [key, value] of Object.entries(info.data)) { if (Array.isArray(value)) info.data[key] = value.toString(); } // check for missing elements const missing = []; for (let i = 0; i < this.requestedElements.length; i++) { const element = this.requestedElements[i]; if (!info[element]) { missing.push(element); } } if (missing.length > 0) this.client.emit('debug', 'Warning: Guild interaction response is missing the following elements: ' + missing.join(', ')); // default position values for (const element of this.requestedElements) { const elements = info[element]; if (!elements) continue; for (let i = 0; i < elements.length; i++) { const item = elements[i]; item.position = (_b = item.position) !== null && _b !== void 0 ? _b : 0; if (element == Common.ElementType.Role) item.managed = (_c = item.managed) !== null && _c !== void 0 ? _c : false; } } yield new Promise((resolve) => { var _a, _b, _c, _d, _e; (_a = this.client.ws) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify({ op: Common.OperationCodes.REQUEST_GUILD_DATA, d: { interactionId: this.id, data: info.data, inGuild: info.inGuild, textChannels: (_b = info.textChannels) !== null && _b !== void 0 ? _b : [], voiceChannels: (_c = info.voiceChannels) !== null && _c !== void 0 ? _c : [], categories: (_d = info.categories) !== null && _d !== void 0 ? _d : [], roles: (_e = info.roles) !== null && _e !== void 0 ? _e : [], } }), resolve); }); }); } } exports.DashboardRequestInteraction = DashboardRequestInteraction; /** * Dashboard changed interaction */ class DashboardChangeInteraction extends DashboardInteraction { constructor(client, options) { super(client, options); let newValue = options.data; // convert string to array for Select and Checkbox types if (typeof options.data == 'string') newValue = options.inputType == Common.ComponentType.Checkbox || options.inputType == Common.ComponentType.Select ? options.data.split(',') : options.data; this.userId = options.userId; this.input = { type: options.inputType, name: options.varname, value: newValue }; this.rawData = options; } /** * Sends an interaction response indicating if the change was successful * @param success Was the change successful? (this will be shown to the user) * @param newValue Optional new value to display on the dashboard input (if 'success' is not false). */ acknowledge(data) { return __awaiter(this, void 0, void 0, function* () { if (!this.id) throw Error('Interaction already acknowledged'); yield new Promise((resolve) => { var _a, _b; (_a = this.client.ws) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify({ op: Common.OperationCodes.ACKNOWLEDGE_INTERACTION, d: { interactionId: this.id, success: (_b = data === null || data === void 0 ? void 0 : data.success) !== null && _b !== void 0 ? _b : true, message: data === null || data === void 0 ? void 0 : data.message, key: this.rawData.varname, value: (data === null || data === void 0 ? void 0 : data.newValue) ? (typeof (data === null || data === void 0 ? void 0 : data.newValue) == 'object' ? data === null || data === void 0 ? void 0 : data.newValue.join(',') : data === null || data === void 0 ? void 0 : data.newValue) : this.rawData.data } }), resolve); }); this.id = null; }); } } exports.DashboardChangeInteraction = DashboardChangeInteraction; __exportStar(require("./common"), exports);