diff --git a/client.js b/client.js index 37608c2..06f5d81 100644 --- a/client.js +++ b/client.js @@ -1,8 +1,7 @@ -import { generateUniqueID } from './modules/baseUtils.mjs'; -import { updateId } from './modules/updateConfig.mjs'; import { ClientNodeConfig } from './modules/clientObjectDefinitions.mjs'; import { initSocketConnection } from './modules/socketClient.mjs'; import { checkForUpdates } from './modules/selfUpdater.mjs' +import startServer from './express/server.mjs'; import dotenv from 'dotenv'; dotenv.config() @@ -11,37 +10,25 @@ var localNodeConfig = new ClientNodeConfig({}) async function boot() { // Check if there have been any updates - await checkForUpdates(); + await checkForUpdates(); if (localNodeConfig.node.nuid === undefined || localNodeConfig.node.nuid === '' || localNodeConfig.node.nuid === '0' || localNodeConfig.node.nuid === 0) { - // Run the first time boot sequence - await firstTimeBoot(); + return new Promise(res => {res(false)}); } // Initialize the socket connection with the server return initSocketConnection(localNodeConfig); } -/** - * Run the first time the client boots on a pc - * @returns {any} - */ -async function firstTimeBoot() { - // Generate a new ID for the node - localNodeConfig.node.nuid = await generateUniqueID(); - console.log(`Generated a new unique ID for this node: '${localNodeConfig.node.nuid}'`); - - // Update the config with the new ID - await updateId(localNodeConfig.node.nuid); - console.log("Updated the config with the new node ID"); - // TODO - Create the config file with the ID given and replace the update above - // TODO - Implement web server so users can update radio systems easily - // TODO - Implement logic to check if the presets are set - return -} - - // Boot the client application boot().then((openSocket) => { - console.log(openSocket, "Booted Sucessfully"); + // Start the web server + startServer(process.env.WEB_SERVER_PORT || 3000, openSocket); + + if (!openSocket) { + console.log(openSocket, "Waiting for setup"); + } + else { + console.log(openSocket, "Booted Sucessfully"); + } }) \ No newline at end of file diff --git a/express/routes/dashboardRoutes.js b/express/routes/dashboardRoutes.js new file mode 100644 index 0000000..aefa114 --- /dev/null +++ b/express/routes/dashboardRoutes.js @@ -0,0 +1,11 @@ +// dashboardRoutes.js + +import express from 'express'; +const router = express.Router(); + +// Define routes +router.get('/', (req, res) => { + res.render('dashboard'); +}); + +export default router; \ No newline at end of file diff --git a/express/routes/setupRoutes.js b/express/routes/setupRoutes.js new file mode 100644 index 0000000..9a31795 --- /dev/null +++ b/express/routes/setupRoutes.js @@ -0,0 +1,136 @@ +import fs from 'fs'; +import path from 'path'; +import express from 'express'; +import { fileURLToPath } from 'url'; +import { generateUniqueID } from '../../modules/baseUtils.mjs'; +import { restartApplication } from '../../modules/selfUpdater.mjs' + +const router = express.Router(); +const __dirname = path.dirname(fileURLToPath(import.meta.url)); // Define __dirname for ESM + +// Array to store information about added systems +let systemsData = []; +let nodeData = {}; + +router.get('/', (req, res) => { + res.render('setup/setup'); +}); + +// Route to serve the page for adding nearby systems +router.get('/add-system', (req, res) => { + res.render('setup/add_system'); +}); + +router.post('/', (req, res) => { + // Handle form submission here + const { clientName, clientLocation, clientCapabilities } = req.body; + + console.log(clientName, clientLocation, clientCapabilities); + + nodeData.clientName = clientName; + nodeData.clientLocation = clientLocation; + nodeData.clientCapabilities = clientCapabilities; + + res.redirect('/setup/add-system'); +}); + +// Route to handle form submission for adding a system +router.post('/add-system', (req, res) => { + const { systemName, frequencies, mode, trunkFile, whitelistFile } = req.body; + + // Store system information for later use + // For now, let's just log the information + console.log('System Name:', systemName); + console.log('Frequencies:', frequencies); + console.log('Mode:', mode); + console.log('Trunk File:', trunkFile); + console.log('Whitelist File:', whitelistFile); + + // Store system information in the array + systemsData.push({ + systemName, + frequencies, + mode, + trunkFile, + whitelistFile + }); + + // Prompt user to add another system or proceed + res.render('setup/prompt_add_another_system'); +}); + +// Route to write collected information to .env file +router.post('/finish-setup', async (req, res) => { + // Write collected information to .env file + // For now, let's just log the collected information + console.log('Collected System Information:', nodeData, systemsData); + + if (!await exportCsv(nodeData)) return res.status(500).send('Error writing to .env file'); + + if (!await exportSystems(systemsData)) return res.status(500).send('Error writing the systems config file'); + + res.send('Setup process completed successfully! Click here for the dashboard when the service restarts.'); + restartApplication(); +}); + +export default router; + + +const exportCsv = (nodeData) => { + const nuid = generateUniqueID(); + console.log(`Generated a new unique ID for this node: '${nuid}'`); + const envData = { + CLIENT_NUID: nuid, + CLIENT_NAME: nodeData.clientName, + CLIENT_LOCATION: nodeData.clientCapabilities, + CLIENT_CAPABILITIES: nodeData.clientCapabilities, + SERVER_IP: "", + SERVER_PORT: 0, + OP25_FULL_PATH: `${__dirname}/op25/op25/gr-op25_repeater/apps`, + CONFIG_PATH: "./config/radioPresets.json", + }; + + // Generate .env file content + const envContent = Object.entries(envData) + .map(([key, value]) => `${key}=${value}`) + .join('\n'); + + // Write to .env file + return new Promise(res => { + fs.writeFile('.env', envContent, (err) => { + if (err) { + console.error('Error writing to .env file:', err); + res(false); + } else { + console.log('.env file updated successfully'); + res(true); + } + }); + }); +} + +const exportSystems = (systemsData) => { + // Write systems data to radioPresets.json + const radioPresetsPath = './config/radioPresets.json'; + const radioPresetsData = {}; + + systemsData.forEach((system, index) => ( + radioPresetsData[system.systemName] = { + frequencies: system.frequencies.split(','), + mode: system.mode, + trunkFile: system.trunkFile || '', + whitelistFile: system.whitelistFile || '' + } + )); + return new Promise(res => { + fs.writeFile(radioPresetsPath, JSON.stringify(radioPresetsData, null, 4), (err) => { + if (err) { + console.error('Error writing to radioPresets.json:', err); + res(false); + } else { + console.log('radioPresets.json updated successfully'); + res(true); + } + }); + }) +} \ No newline at end of file diff --git a/express/server.mjs b/express/server.mjs new file mode 100644 index 0000000..5769c73 --- /dev/null +++ b/express/server.mjs @@ -0,0 +1,60 @@ +import express from 'express'; +import http from 'http'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import bodyParser from 'body-parser'; + +import setupRoutes from './routes/setupRoutes.js'; +import dashboardRoutes from './routes/dashboardRoutes.js'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); // Define __dirname for ESM + +export var isSetupComplete = false; + +const app = express(); +const server = http.createServer(app); + +// Start the server +const startServer = (port, openSocket) => { + if (openSocket) isSetupComplete = true; + + server.listen(port, () => { + console.log(`Server running on port ${port}`); + }); +}; + +export default startServer; + +// Set EJS as the default template engine +app.set('view engine', 'ejs'); + +// Set the views directory to express/views +const viewsPath = path.join(__dirname, 'views'); +app.set('views', viewsPath); + +// Use body-parser middleware to parse JSON requests +app.use(bodyParser.json()); + +// Use body-parser middleware to parse URL-encoded form data +app.use(bodyParser.urlencoded({ extended: true })); + +// Define static folder for serving HTML, CSS, and client-side JavaScript files +const staticPath = path.join(__dirname, 'public'); +app.use(express.static(staticPath)); + +// ---------------- Defualt Route +app.get('/', (req, res) => { + if (!isSetupComplete) { + return res.redirect('/setup'); + } + else { + return res.redirect('/dashboard'); + } +}); + +// ---------------- Routers +// Use the setup router for '/setup' routes +app.use('/setup', setupRoutes); + +// Use the dashboard router for '/dashboard' routes +app.use('/dashboard', dashboardRoutes); \ No newline at end of file diff --git a/express/views/dashboard.ejs b/express/views/dashboard.ejs new file mode 100644 index 0000000..0f5723c --- /dev/null +++ b/express/views/dashboard.ejs @@ -0,0 +1,15 @@ + + + + + + + + Dashboard + + +

Welcome to the Dashboard

+

This is a very basic dashboard.

+ + + diff --git a/express/views/setup/add_system.ejs b/express/views/setup/add_system.ejs new file mode 100644 index 0000000..7ada5c4 --- /dev/null +++ b/express/views/setup/add_system.ejs @@ -0,0 +1,34 @@ + + + + + + + + Add Nearby Systems + + +

Add Nearby Systems

+
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + diff --git a/express/views/setup/prompt_add_another_system.ejs b/express/views/setup/prompt_add_another_system.ejs new file mode 100644 index 0000000..7562b21 --- /dev/null +++ b/express/views/setup/prompt_add_another_system.ejs @@ -0,0 +1,19 @@ + + + + + + + + Add Another System? + + +

Add Another System?

+
+ +
+
+ +
+ + diff --git a/express/views/setup/setup.ejs b/express/views/setup/setup.ejs new file mode 100644 index 0000000..aa52ed7 --- /dev/null +++ b/express/views/setup/setup.ejs @@ -0,0 +1,25 @@ + + + + + + + + Setup + + +

Setup

+
+ + +
+ + +
+ + +
+ +
+ + diff --git a/modules/selfUpdater.mjs b/modules/selfUpdater.mjs index 080bab3..0a9f882 100644 --- a/modules/selfUpdater.mjs +++ b/modules/selfUpdater.mjs @@ -51,7 +51,7 @@ export const checkForUpdates = async () => { } // Function to restart the application -const restartApplication = () => { +export const restartApplication = () => { console.log('Restarting the application...'); restartService('discord-radio-bot'); } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b9774f7..3a370d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,10 +10,10 @@ "license": "ISC", "dependencies": { "@discordjs/voice": "^0.16.1", - "chai-http": "^4.4.0", "convert-units": "^2.3.4", "discord.js": "^14.14.1", "dotenv": "^16.3.1", + "ejs": "^3.1.10", "express": "^4.19.2", "libsodium-wrappers": "^0.7.13", "prism-media": "^1.3.5", @@ -24,6 +24,7 @@ }, "devDependencies": { "chai": "^5.1.0", + "chai-http": "^4.4.0", "mocha": "^10.4.0", "typescript": "^5.3.3" } @@ -240,7 +241,8 @@ "node_modules/@types/chai": { "version": "4.3.14", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.14.tgz", - "integrity": "sha512-Wj71sXE4Q4AkGdG9Tvq1u/fquNz9EdG4LIJMwVVII7ashjD/8cf8fyIfJAjRr6YcsXnSE8cOGQPq1gqeR8z+3w==" + "integrity": "sha512-Wj71sXE4Q4AkGdG9Tvq1u/fquNz9EdG4LIJMwVVII7ashjD/8cf8fyIfJAjRr6YcsXnSE8cOGQPq1gqeR8z+3w==", + "dev": true }, "node_modules/@types/cookie": { "version": "0.4.1", @@ -250,7 +252,8 @@ "node_modules/@types/cookiejar": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", - "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==" + "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", + "dev": true }, "node_modules/@types/cors": { "version": "2.8.17", @@ -272,6 +275,7 @@ "version": "4.1.13", "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.13.tgz", "integrity": "sha512-YIGelp3ZyMiH0/A09PMAORO0EBGlF5xIKfDpK74wdYvWUs2o96b5CItJcWPdH409b7SAXIIG6p8NdU/4U2Maww==", + "dev": true, "dependencies": { "@types/cookiejar": "*", "@types/node": "*" @@ -364,7 +368,8 @@ "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true }, "node_modules/assertion-error": { "version": "2.0.1", @@ -375,10 +380,16 @@ "node": ">=12" } }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true }, "node_modules/balanced-match": { "version": "1.0.2", @@ -525,6 +536,7 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/chai-http/-/chai-http-4.4.0.tgz", "integrity": "sha512-uswN3rZpawlRaa5NiDUHcDZ3v2dw5QgLyAwnQ2tnVNuP7CwIsOFuYJ0xR1WiR7ymD4roBnJIzOUep7w9jQMFJA==", + "dev": true, "dependencies": { "@types/chai": "4", "@types/superagent": "4.1.13", @@ -543,6 +555,7 @@ "version": "6.12.1", "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.1.tgz", "integrity": "sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==", + "dev": true, "dependencies": { "side-channel": "^1.0.6" }, @@ -572,6 +585,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/charset/-/charset-1.0.1.tgz", "integrity": "sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg==", + "dev": true, "engines": { "node": ">=4.0.0" } @@ -645,6 +659,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -656,10 +671,16 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -704,7 +725,8 @@ "node_modules/cookiejar": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", - "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==" + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true }, "node_modules/cors": { "version": "2.8.5", @@ -775,6 +797,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, "engines": { "node": ">=0.4.0" } @@ -800,6 +823,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, "dependencies": { "asap": "^2.0.0", "wrappy": "1" @@ -887,6 +911,20 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -1062,7 +1100,16 @@ "node_modules/fast-safe-stringify": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dependencies": { + "minimatch": "^5.0.1" + } }, "node_modules/fill-range": { "version": "7.0.1", @@ -1135,6 +1182,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -1148,6 +1196,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", + "dev": true, "dependencies": { "dezalgo": "^1.0.4", "hexoid": "^1.0.0", @@ -1342,6 +1391,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "dev": true, "engines": { "node": ">=8" } @@ -1390,6 +1440,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", "integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==", + "dev": true, "engines": { "node": ">=4" } @@ -1447,6 +1498,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-2.0.0.tgz", "integrity": "sha512-9MTn0dteHETtyUx8pxqMwg5hMBi3pvlyglJ+b79KOCca0po23337LbVV2Hl4xmMvfw++ljnO0/+5G6G+0Szh6g==", + "dev": true, "dependencies": { "ip-regex": "^2.0.0" }, @@ -1484,6 +1536,43 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/jake": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.1.tgz", + "integrity": "sha512-61btcOHNnLnsOdtLgA5efqQWjnSi/vow5HbI7HMdKKWqvrKR1bLK3BPlJn9gcSaP2ewuamUSMB5XEy76KUIS2w==", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jake/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -1717,6 +1806,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -2173,6 +2263,7 @@ "version": "7.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -2400,6 +2491,7 @@ "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.1.2.tgz", "integrity": "sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==", "deprecated": "Please upgrade to v9.0.0+ as we have fixed a public vulnerability with formidable dependency. Note that v9.0.0+ requires Node.js v14.18.0+. See https://github.com/ladjs/superagent/pull/1800 for insight. This project is supported and maintained by the team at Forward Email @ https://forwardemail.net", + "dev": true, "dependencies": { "component-emitter": "^1.3.0", "cookiejar": "^2.1.4", @@ -2420,6 +2512,7 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, "bin": { "mime": "cli.js" }, @@ -2599,7 +2692,8 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/yargs": { "version": "17.7.2", diff --git a/package.json b/package.json index c5f0f34..fc9fd9f 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "convert-units": "^2.3.4", "discord.js": "^14.14.1", "dotenv": "^16.3.1", + "ejs": "^3.1.10", "express": "^4.19.2", "libsodium-wrappers": "^0.7.13", "prism-media": "^1.3.5", @@ -24,9 +25,9 @@ "socket.io-client": "^4.7.2" }, "devDependencies": { - "chai-http": "^4.4.0", "chai": "^5.1.0", + "chai-http": "^4.4.0", "mocha": "^10.4.0", "typescript": "^5.3.3" } -} \ No newline at end of file +}