Checkpoint; Full rewrite is underway, this shouldn't take long!

This commit is contained in:
Christopher Cookman 2025-01-25 07:40:09 -07:00
parent 3ed7d3aa58
commit 33d1c8ae9c
21 changed files with 895 additions and 1985 deletions

2
.gitignore vendored
View file

@ -137,3 +137,5 @@ test.js
embeds.json
pageGroups.json
.ssh/
old/

42
TODO.md Normal file
View file

@ -0,0 +1,42 @@
# Bot Checklist
## General Commands
- [X] **/whoami** - Get your extension info if you have one.
- [X] **/new** - Get an extension on the LiteNet Phone System.
- [X] **/delete** - Remove your extension from the LiteNet Phone System.
- [ ] **/list** - List all extensions on the LiteNet Phone System.
- [ ] **/button** - Send the "Get an extension" button! *(Requires default_member_permissions: 0)*
## Admin Commands
*(Requires default_member_permissions: 0)*
- [ ] **/admin**
- [ ] **silence** - Kill all ongoing calls.
- [ ] **reload** - Run an Asterisk reload.
- [ ] **reboot** - Reboot the server. *(LAST RESORT)*
## Developer Commands
*(Requires default_member_permissions: 0)*
- [ ] **/dev**
- [ ] **fwconsole** - Run an `fwconsole` command.
- [ ] **command** (required) - The command to run.
- [ ] **asterisk** - Run an Asterisk CLI command.
- [ ] **command** (required) - The command to run.
- [ ] **shell** - Run a shell command.
- [ ] **command** (required) - The command to run.
- [ ] **restart** - Restart the bot.
## Call Detail Records (CDR)
- [ ] **/cdr** - Get the call detail records for your extension.
- [ ] **start_date** (optional) - The start date for the CDR (mm/dd/yyyy).
- [ ] **end_date** (optional) - The end date for the CDR (mm/dd/yyyy).
## Context Menu Commands
- [ ] **Lookup Extension** - *(Type: 2)*
- [ ] **Create Extension** - *(Type: 2, Requires default_member_permissions: 0)*
- [ ] **Delete Extension** - *(Type: 2, Requires default_member_permissions: 0)*
## Buttons (On button message)
- **Get an Extension** - Sends the "Get an extension" button.
- **See Your Info** - Sends the "See your info" button.
- **Delete Your Extension** - Sends the "Delete your extension" button.

View file

@ -1,13 +0,0 @@
{
"name": "name",
"description": "Change your extension's name (Defaults to your Discord name)",
"type": 1,
"options": [
{
"name": "name",
"description": "The new name for your extension",
"type": 3,
"required": false
}
]
},

View file

@ -1,4 +1,4 @@
[
module.exports = [
{
"name": "whoami",
"description": "Get your extension info if you have one",
@ -18,13 +18,7 @@
"name": "confirm",
"description": "Confirm that you want to delete your extension. THIS CANNOT BE UNDONE!",
"type": 5,
"required": true,
"choices": [
{
"name": "yes",
"value": "yes"
}
]
"required": true
}
]
},
@ -39,19 +33,20 @@
"type": 1,
"default_member_permissions": 0
},
{
"name": "name",
"description": "Change your extension's name (Defaults to your Discord name)",
"type": 1,
"options": [
{
"name": "name",
"description": "The new name for your extension",
"type": 3,
"required": false
}
]
},
// TODO: Find a way to make the name command work again. Sadge
// {
// "name": "name",
// "description": "Change your extension's name (Defaults to your Discord name)",
// "type": 1,
// "options": [
// {
// "name": "name",
// "description": "The new name for your extension",
// "type": 3,
// "required": false
// }
// ]
// },
{
"name": "admin",
"description": "Admin only commands",
@ -154,17 +149,29 @@
]
},
{
"name": "Lookup Extension",
"type": 2
},
"name": "lookup",
"description": "Find extension by Discord user",
"type": 1,
"options": [
{
"name": "Create Extension",
"type": 2,
"default_member_permissions": 0
},
{
"name": "Delete Extension",
"type": 2,
"default_member_permissions": 0
"name": "user",
"description": "The Discord user to lookup",
"type": 6,
"required": true
}
]
},
{
"name": "whois",
"description": "Find Discord user by extension",
"type": 1,
"options": [
{
"name": "extension",
"description": "The extension to lookup",
"type": 4,
"required": true
}
]
}
]

View file

@ -1,39 +0,0 @@
{
"ntfyUrl": "ntfy-url",
"freepbx": {
"server": "sip-server-ip",
"url": "pbx-api-url",
"clientid": "gql-client-id",
"allowedscopes": "gql",
"secret": "gql-secret",
"startExt": 1000
},
"discord": {
"token": "bot-token",
"guildId": "guild-id",
"roleId": "user-role",
"logId": "log-channel",
"extList": "extension-list-channel",
"developers": [
"your-user-id"
]
},
"mariadb": {
"host": "db-hostname0here",
"user": "bot",
"password": "bot",
"database": "asterisk",
"connectionLimit": 5
},
"cdrdb": {
"host": "db-hostname-here",
"user": "bot",
"password": "bot",
"database": "asteriskcdrdb",
"connectionLimit": 5
},
"status": {
"interval": 60,
"url": "uptime-kuma-link"
}
}

View file

@ -1,9 +0,0 @@
{
"controls": [
{
"title": "Phone System Controls",
"color": 205442,
"description": "Use the buttons below to control your extension!"
}
]
}

185
freepbx.js Normal file
View file

@ -0,0 +1,185 @@
const { FreepbxGqlClient, gql } = require("freepbx-graphql-client");
class FreepbxManager {
/**
* Creates an instance of the FreepbxGqlClient and initializes the connection pool.
*
* @param {Object} config - Configuration object for the FreepbxGqlClient.
* @param {string} config.url - The URL of the FreePBX GraphQL endpoint.
* @param {string} config.clientId - The client ID for authentication.
* @param {string} config.clientSecret - The client secret for authentication.
* @param {Object} config.dbPool - The connection pool for managing database connections.
*/
constructor(config) {
this.client = new FreepbxGqlClient(config.url, {
client: {
id: config.clientId,
secret: config.clientSecret,
},
});
this.pool = config.dbPool;
if (!this.pool) {
throw new Error("Connection pool is required");
}
}
async getExtension(ext) {
ext = String(ext);
const query = gql`
query fetchExtension($extensionId: ID!) {
fetchExtension(extensionId: $extensionId) {
user {
extension
name
extPassword
voicemail
}
}
}
`;
const variables = {
extensionId: ext.match(/\d+/)[0],
};
return await this.client.request(query, variables);
}
async listExtensions() {
const query = gql`
query {
fetchAllExtensions {
extension {
user {
extension
name
}
}
}
}
`;
return await this.client.request(query);
}
async addExtension(ext, name) {
ext = String(ext);
name = String(name);
const query = gql`
mutation addExtension($ext: ID!, $name: String!, $vmPassword: String!) {
addExtension(input: {
extensionId: $ext
name: $name
vmEnable: true
vmPassword: $vmPassword
email: ""
maxContacts: "100"
umEnable: false
}) {
status
}
}
`;
const variables = {
ext,
name,
vmPassword: ext,
};
return await this.client.request(query, variables);
}
async deleteExtension(ext) {
ext = String(ext);
const query = gql`
mutation deleteExtension($ext: ID!) {
deleteExtension(input: { extensionId: $ext }) {
status
}
}
`;
const variables = {
ext,
};
const fpbxQuery = this.client.request(query, variables);
const dbQuery = this.pool.query('DELETE FROM paging_groups WHERE ext = ?', [ext]);
return await Promise.all([fpbxQuery, dbQuery]);
}
async reload() {
const query = gql`
mutation {
doreload(input: { clientMutationId: "${Math.random().toString(36).substring(2, 14)}" }) {
status
}
}
`;
return await this.client.request(query);
}
// async updateName(ext, name) {
// const query = gql`
// mutation updateName($ext: ID!, $name: String!) {
// updateExtension(input: {extensionId: $ext, name: $name}) {
// status,
// message
// }
// }`;
// const variables = {
// ext,
// name,
// };
// return await this.client.request(query, variables);
// }
// TODO: Implement updateName method, Current implementation resets extension for some reason
async joinPageGroup(ext, pageGroup) {
const [lookup] = await this.pool.query('SELECT * FROM paging_groups WHERE page_number = ? AND ext = ?', [pageGroup, ext]);
if (lookup) {
return false;
}
await this.pool.query('INSERT INTO paging_groups (page_number, ext) VALUES (?, ?)', [pageGroup, ext]);
return true;
};
async leavePageGroup(ext, pageGroup) {
const [lookup] = await this.pool.query('SELECT * FROM paging_groups WHERE page_number = ? AND ext = ?', [pageGroup, ext]);
if (!lookup) {
return false;
}
await this.pool.query('DELETE FROM paging_groups WHERE page_number = ? AND ext = ?', [pageGroup, ext]);
return true;
};
async getNextAvailableExtension() {
const extList = await this.listExtensions();
const exts = extList.fetchAllExtensions.extension;
const startExt = process.env.START_EXT ? parseInt(process.env.START_EXT, 10) : 1000;
const existingExts = exts.map(ext => parseInt(ext.user.extension, 10)).sort((a, b) => a - b);
let nextExt = startExt;
for (let i = 0; i < existingExts.length; i++) {
if (existingExts[i] !== nextExt) {
break;
}
nextExt++;
}
return nextExt;
}
}
module.exports = FreepbxManager;

View file

@ -1,97 +0,0 @@
// Some random functions, as to not clutter the main file
// Generate GraphQL query
const generateQuery = (type, args) => {
switch (type) {
case 'lookup':
return minifyQuery(`query {
fetchExtension(extensionId: "${args.ext}") {
user {
extension
name
extPassword
voicemail
}
}
fetchVoiceMail(extensionId: "${args.ext}") {
password
email
}
}`);
break;
case 'list':
return minifyQuery(`query {
fetchAllExtensions {
extension {
user {
extension
name
}
}
}
}`);
break;
case 'add':
return minifyQuery(`mutation {
addExtension(input: {
extensionId: "${args.ext}"
name: "${args.name}"
email: "${args.uid}"
vmEnable: true
vmPassword: "${args.ext}"
maxContacts: "5"
umEnable: false
}) {
status
}
}`);
break;
case 'delete':
return minifyQuery(`mutation {
deleteExtension(input: {extensionId: ${args.ext}}) {
status
}
}`);
break;
case 'reload':
return minifyQuery(`mutation {
doreload(input: {clientMutationId: "${args.id}"}) {
status
}
}`);
break;
case 'update_name':
return minifyQuery(`mutation {
updateCoreUser (input: {extension: ${args.ext}, name: "${args.name}", noanswer_cid: "", busy_cid: "", chanunavail_cid: "", busy_dest: "", noanswer_dest: "", chanunavail_dest: ""}) {
coreuser {
name
}
}
}`);
}
}
// minify query function
const minifyQuery = (query) => {
return query.replace(/\s+/g, ' ').trim();
}
module.exports = {
generateQuery,
minifyQuery,
// Input validation
validateInput: function (input, type) {
switch (type) {
case 'extention':
// Check if input is a 3 digit number
if (input.length != 3) {
return false;
}
if (isNaN(input)) {
return false;
}
return true;
break;
}
},
}

1769
index.js

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,30 @@
const pool = global.pool
const fpbx = global.fpbx
const client = global.client
const log = global.log
module.exports = {};
module.exports.execute = async (interaction) => {
const [lookup] = await pool.query('SELECT * FROM discord_users WHERE discordId = ?', [interaction.user.id]);
if (!lookup) {
await interaction.reply({ content: `We're sorry, It doesn't look like you have an extension!`, ephemeral: true });
return;
}
if (interaction.options.getBoolean("confirm") !== true) {
await interaction.reply({ content: `You must confirm you want to delete your extension!`, ephemeral: true });
return;
}
fpbx.deleteExtension(lookup.extension).then(async (res) => {
if (res[0].deleteExtension.status != true) {
await interaction.reply({ content: `Something went wrong :(`, ephemeral: true });
return;
}
await pool.query('DELETE FROM discord_users WHERE discordId = ?', [interaction.user.id]);
await fpbx.reload();
await interaction.reply({ content: `Extension ${lookup.extension} deleted!`, ephemeral: true });
}).catch(async (error) => {
log.error(error);
await interaction.reply({ content: 'There was an error while deleting your extension!', ephemeral: true });
});
}

View file

@ -0,0 +1,36 @@
const Discord = require('discord.js');
const pool = global.pool
const fpbx = global.fpbx
const client = global.client
const log = global.log
module.exports = {};
module.exports.execute = async (interaction) => {
const lookup = await pool.query('SELECT * FROM discord_users');
// lookup: [ { extension: '1001', discord_id: '1234567890' } ]
const embeds = [];
let description = '';
lookup.forEach((row, index) => {
const line = `${row.extension}: <@${row.discordId}>\n`;
if (description.length > 2048) {
embeds.push({
description
});
description = '';
}
description += line;
});
if (description.length > 0) {
embeds.push({
description
});
}
embeds.forEach(async (embed) => {
await interaction.user.send({ embeds: [embed] });
})
await interaction.reply({ ephemeral: true, content: "Check your DMs!" });
}

View file

@ -0,0 +1,19 @@
const pool = global.pool
const fpbx = global.fpbx
const client = global.client
const log = global.log
module.exports = {};
module.exports.execute = async (interaction) => {
const findUser = interaction.options.getUser('user');
const [lookup] = await pool.query('SELECT * FROM discord_users WHERE discordId = ?', [findUser.id]);
if (!lookup) {
await interaction.reply({ content: `No extension found for ${findUser.username}`, ephemeral: true });
return;
}
await interaction.reply({ content: `${findUser} has extension ${lookup.extension}`, ephemeral: true });
}

View file

@ -0,0 +1,40 @@
const pool = global.pool
const fpbx = global.fpbx
const client = global.client
const log = global.log
module.exports = {};
module.exports.execute = async (interaction) => {
await interaction.deferReply({ ephemeral: true });
const [lookup] = await pool.query('SELECT * FROM discord_users WHERE discordId = ?', [interaction.user.id]);
if (lookup) {
await interaction.editReply({ content: `You already have an extension, it's ${lookup.extension}!`, ephemeral: true });
return;
}
await interaction.editReply({ content: `Finding available extension`, ephemeral: true });
fpbx.getNextAvailableExtension().then(async (nextExt) => {
await interaction.editReply({ content: `Found ${nextExt}. Creating..`, ephemeral: true });
fpbx.addExtension(nextExt, interaction.user.username).then(async (res) => {
if (res.addExtension.status != true) {
await interaction.editReply({ content: `Something went wrong :(`, ephemeral: true });
return;
}
await pool.query('INSERT INTO discord_users (discordId, extension) VALUES (?, ?)', [interaction.user.id, nextExt]);
await interaction.editReply({ content: `Extension ${nextExt} created! Getting info..`, ephemeral: true });
await fpbx.reload();
const extInfo = await fpbx.getExtension(nextExt);
await interaction.editReply({ embeds: [{
title: "Your Extension Info",
description: `**PBX Address:** \`${process.env.PBX_HOSTNAME}\`\n**Extension:** \`${extInfo.fetchExtension.user.extension}\`\n**Name:** \`${extInfo.fetchExtension.user.name}\`\n**Password:** ||\`${extInfo.fetchExtension.user.extPassword}\`||`,
color: 0x00ff00
}], ephemeral: true })
}).catch(async (error) => {
log.error(error);
await interaction.editReply({ content: 'There was an error while creating your extension!', ephemeral: true });
});
}).catch(async (error) => {
log.error(error);
await interaction.editReply({ content: 'There was an error while creating your extension!', ephemeral: true });
});
}

View file

@ -0,0 +1,25 @@
const pool = global.pool
const fpbx = global.fpbx
const client = global.client
const log = global.log
module.exports = {};
module.exports.execute = async (interaction) => {
const [lookup] = await pool.query('SELECT * FROM discord_users WHERE discordId = ?', [interaction.user.id]);
if (!lookup) {
await interaction.reply({ content: `We're sorry, It doesn't look like you have an extension!`, ephemeral: true });
return;
}
const extInfo = await fpbx.getExtension(lookup.extension);
return await interaction.reply({
ephemeral: true, embeds: [
{
title: "Your Extension Info",
description: `**PBX Address:** \`${process.env.PBX_HOSTNAME}\`\n**Extension:** \`${extInfo.fetchExtension.user.extension}\`\n**Name:** \`${extInfo.fetchExtension.user.name}\`\n**Password:** ||\`${extInfo.fetchExtension.user.extPassword}\`||`,
color: 0x00ff00
}
]
});
}

View file

@ -0,0 +1,19 @@
const pool = global.pool
const fpbx = global.fpbx
const client = global.client
const log = global.log
module.exports = {};
module.exports.execute = async (interaction) => {
const findExt = interaction.options.getInteger('extension');
const [lookup] = await pool.query('SELECT * FROM discord_users WHERE extension = ?', [findExt]);
if (!lookup) {
await interaction.reply({ content: `No linked Discord account found for extension ${findExt}`, ephemeral: true });
return;
}
await interaction.reply({ content: `${findExt} belongs to <@${lookup.discordId}>`, ephemeral: true });
}

72
migrations.js Normal file
View file

@ -0,0 +1,72 @@
const mariadb = require('mariadb');
const fs = require('fs');
const path = require('path');
const util = require("util")
function runMigrations(pool) {
return new Promise((resolve, reject) => {
let connection;
pool.getConnection()
.then(conn => {
connection = conn;
// Ensure a migrations table exists to track applied migrations
return connection.query(`CREATE TABLE IF NOT EXISTS migrations (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);`);
})
.then(() => {
// Read all migration files
const migrationDir = path.join(__dirname, 'migrations');
const files = fs.readdirSync(migrationDir).sort(); // Sort to apply in order
return files.reduce((promise, file) => {
return promise.then(() => {
const migrationName = path.basename(file);
// Check if the migration has already been applied
return connection.query(
'SELECT 1 FROM migrations WHERE name = ? LIMIT 1',
[migrationName]
).then(([rows]) => {
if (Object.keys(rows || {}).length > 0) {
//console.log(`Skipping already applied migration: ${migrationName}`);
return; // Skip this migration
}
// Read and execute the migration SQL
const migrationPath = path.join(migrationDir, file);
const sql = fs.readFileSync(migrationPath, 'utf8');
return connection.query(sql).then(() => {
// Record the applied migration
return connection.query(
'INSERT INTO migrations (name) VALUES (?)',
[migrationName]
).then(() => {
console.log(`Applied migration: ${migrationName}`);
});
});
});
});
}, Promise.resolve());
})
.then(() => {
console.log('All migrations applied successfully!');
resolve();
})
.catch(err => {
console.error('Error running migrations:', err);
reject(err);
})
.finally(() => {
if (connection) connection.release();
});
});
}
module.exports = runMigrations

View file

@ -0,0 +1 @@
ALTER TABLE users ADD CONSTRAINT unique_extension UNIQUE (extension);

View file

@ -0,0 +1,4 @@
CREATE TABLE IF NOT EXISTS discord_users (
extension VARCHAR(20) PRIMARY KEY,
discordId VARCHAR(25) NOT NULL
);

392
package-lock.json generated
View file

@ -12,6 +12,7 @@
"axios": "^1.6.0",
"colors": "^1.4.0",
"discord.js": "14.14.1",
"dotenv": "^16.4.7",
"freepbx-graphql-client": "^0.1.1",
"mariadb": "^3.2.0",
"ping": "^0.4.4",
@ -20,85 +21,230 @@
}
},
"node_modules/@discordjs/builders": {
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.5.tgz",
"integrity": "sha512-SdweyCs/+mHj+PNhGLLle7RrRFX9ZAhzynHahMCLqp5Zeq7np7XC6/mgzHc79QoVlQ1zZtOkTTiJpOZu5V8Ufg==",
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.10.0.tgz",
"integrity": "sha512-ikVZsZP+3shmVJ5S1oM+7SveUCK3L9fTyfA8aJ7uD9cNQlTqF+3Irbk2Y22KXTb3C3RNUahRkSInClJMkHrINg==",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/formatters": "^0.3.2",
"@discordjs/util": "^1.0.1",
"@sapphire/shapeshift": "^3.9.2",
"discord-api-types": "0.37.50",
"@discordjs/formatters": "^0.6.0",
"@discordjs/util": "^1.1.1",
"@sapphire/shapeshift": "^4.0.0",
"discord-api-types": "^0.37.114",
"fast-deep-equal": "^3.1.3",
"ts-mixer": "^6.0.3",
"tslib": "^2.6.1"
"ts-mixer": "^6.0.4",
"tslib": "^2.6.3"
},
"engines": {
"node": ">=16.11.0"
},
"funding": {
"url": "https://github.com/discordjs/discord.js?sponsor"
}
},
"node_modules/@discordjs/builders/node_modules/@discordjs/formatters": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.6.0.tgz",
"integrity": "sha512-YIruKw4UILt/ivO4uISmrGq2GdMY6EkoTtD0oS0GvkJFRZbTSdPhzYiUILbJ/QslsvC9H9nTgGgnarnIl4jMfw==",
"license": "Apache-2.0",
"dependencies": {
"discord-api-types": "^0.37.114"
},
"engines": {
"node": ">=16.11.0"
},
"funding": {
"url": "https://github.com/discordjs/discord.js?sponsor"
}
},
"node_modules/@discordjs/builders/node_modules/discord-api-types": {
"version": "0.37.117",
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.117.tgz",
"integrity": "sha512-d+Z6RKd7v3q22lsil7yASucqMfVVV0s0XSqu3cw7kyHVXiDO/mAnqMzqma26IYnIm2mk3TlupYJDGrdL908ZKA==",
"license": "MIT"
},
"node_modules/@discordjs/builders/node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/@discordjs/collection": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz",
"integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==",
"license": "Apache-2.0",
"engines": {
"node": ">=16.11.0"
}
},
"node_modules/@discordjs/formatters": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.2.tgz",
"integrity": "sha512-lE++JZK8LSSDRM5nLjhuvWhGuKiXqu+JZ/DsOR89DVVia3z9fdCJVcHF2W/1Zxgq0re7kCzmAJlCMMX3tetKpA==",
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.3.tgz",
"integrity": "sha512-wTcI1Q5cps1eSGhl6+6AzzZkBBlVrBdc9IUhJbijRgVjCNIIIZPgqnUj3ntFODsHrdbGU8BEG9XmDQmgEEYn3w==",
"license": "Apache-2.0",
"dependencies": {
"discord-api-types": "0.37.50"
"discord-api-types": "0.37.61"
},
"engines": {
"node": ">=16.11.0"
}
},
"node_modules/@discordjs/rest": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.0.1.tgz",
"integrity": "sha512-/eWAdDRvwX/rIE2tuQUmKaxmWeHmGealttIzGzlYfI4+a7y9b6ZoMp8BG/jaohs8D8iEnCNYaZiOFLVFLQb8Zg==",
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.4.2.tgz",
"integrity": "sha512-9bOvXYLQd5IBg/kKGuEFq3cstVxAMJ6wMxO2U3wjrgO+lHv8oNCT+BBRpuzVQh7BoXKvk/gpajceGvQUiRoJ8g==",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/collection": "^1.5.3",
"@discordjs/util": "^1.0.1",
"@sapphire/async-queue": "^1.5.0",
"@sapphire/snowflake": "^3.5.1",
"@vladfrangu/async_event_emitter": "^2.2.2",
"discord-api-types": "0.37.50",
"magic-bytes.js": "^1.0.15",
"tslib": "^2.6.1",
"undici": "5.22.1"
"@discordjs/collection": "^2.1.1",
"@discordjs/util": "^1.1.1",
"@sapphire/async-queue": "^1.5.3",
"@sapphire/snowflake": "^3.5.3",
"@vladfrangu/async_event_emitter": "^2.4.6",
"discord-api-types": "^0.37.114",
"magic-bytes.js": "^1.10.0",
"tslib": "^2.6.3",
"undici": "6.19.8"
},
"engines": {
"node": ">=16.11.0"
"node": ">=18"
},
"funding": {
"url": "https://github.com/discordjs/discord.js?sponsor"
}
},
"node_modules/@discordjs/rest/node_modules/@discordjs/collection": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz",
"integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==",
"license": "Apache-2.0",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/discordjs/discord.js?sponsor"
}
},
"node_modules/@discordjs/rest/node_modules/@sapphire/snowflake": {
"version": "3.5.5",
"resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.5.tgz",
"integrity": "sha512-xzvBr1Q1c4lCe7i6sRnrofxeO1QTP/LKQ6A6qy0iB4x5yfiSfARMEQEghojzTNALDTcv8En04qYNIco9/K9eZQ==",
"license": "MIT",
"engines": {
"node": ">=v14.0.0",
"npm": ">=7.0.0"
}
},
"node_modules/@discordjs/rest/node_modules/discord-api-types": {
"version": "0.37.117",
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.117.tgz",
"integrity": "sha512-d+Z6RKd7v3q22lsil7yASucqMfVVV0s0XSqu3cw7kyHVXiDO/mAnqMzqma26IYnIm2mk3TlupYJDGrdL908ZKA==",
"license": "MIT"
},
"node_modules/@discordjs/rest/node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/@discordjs/rest/node_modules/undici": {
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.19.8.tgz",
"integrity": "sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==",
"license": "MIT",
"engines": {
"node": ">=18.17"
}
},
"node_modules/@discordjs/util": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.1.tgz",
"integrity": "sha512-d0N2yCxB8r4bn00/hvFZwM7goDcUhtViC5un4hPj73Ba4yrChLSJD8fy7Ps5jpTLg1fE9n4K0xBLc1y9WGwSsA==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.1.1.tgz",
"integrity": "sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g==",
"license": "Apache-2.0",
"engines": {
"node": ">=16.11.0"
"node": ">=18"
},
"funding": {
"url": "https://github.com/discordjs/discord.js?sponsor"
}
},
"node_modules/@discordjs/ws": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.0.1.tgz",
"integrity": "sha512-avvAolBqN3yrSvdBPcJ/0j2g42ABzrv3PEL76e3YTp2WYMGH7cuspkjfSyNWaqYl1J+669dlLp+YFMxSVQyS5g==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.0.tgz",
"integrity": "sha512-QH5CAFe3wHDiedbO+EI3OOiyipwWd+Q6BdoFZUw/Wf2fw5Cv2fgU/9UEtJRmJa9RecI+TAhdGPadMaEIur5yJg==",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/collection": "^1.5.3",
"@discordjs/rest": "^2.0.1",
"@discordjs/util": "^1.0.1",
"@sapphire/async-queue": "^1.5.0",
"@types/ws": "^8.5.5",
"@vladfrangu/async_event_emitter": "^2.2.2",
"discord-api-types": "0.37.50",
"tslib": "^2.6.1",
"ws": "^8.13.0"
"@discordjs/collection": "^2.1.0",
"@discordjs/rest": "^2.4.1",
"@discordjs/util": "^1.1.0",
"@sapphire/async-queue": "^1.5.2",
"@types/ws": "^8.5.10",
"@vladfrangu/async_event_emitter": "^2.2.4",
"discord-api-types": "^0.37.114",
"tslib": "^2.6.2",
"ws": "^8.17.0"
},
"engines": {
"node": ">=16.11.0"
},
"funding": {
"url": "https://github.com/discordjs/discord.js?sponsor"
}
},
"node_modules/@discordjs/ws/node_modules/@discordjs/collection": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.1.1.tgz",
"integrity": "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==",
"license": "Apache-2.0",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/discordjs/discord.js?sponsor"
}
},
"node_modules/@discordjs/ws/node_modules/@types/ws": {
"version": "8.5.14",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.14.tgz",
"integrity": "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@discordjs/ws/node_modules/discord-api-types": {
"version": "0.37.117",
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.117.tgz",
"integrity": "sha512-d+Z6RKd7v3q22lsil7yASucqMfVVV0s0XSqu3cw7kyHVXiDO/mAnqMzqma26IYnIm2mk3TlupYJDGrdL908ZKA==",
"license": "MIT"
},
"node_modules/@discordjs/ws/node_modules/ws": {
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/@fastify/busboy": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
"license": "MIT",
"engines": {
"node": ">=14"
}
},
"node_modules/@gar/promisify": {
@ -151,31 +297,33 @@
}
},
"node_modules/@sapphire/async-queue": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz",
"integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==",
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.5.tgz",
"integrity": "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg==",
"license": "MIT",
"engines": {
"node": ">=v14.0.0",
"npm": ">=7.0.0"
}
},
"node_modules/@sapphire/shapeshift": {
"version": "3.9.2",
"resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz",
"integrity": "sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-4.0.0.tgz",
"integrity": "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"lodash": "^4.17.21"
},
"engines": {
"node": ">=v14.0.0",
"npm": ">=7.0.0"
"node": ">=v16"
}
},
"node_modules/@sapphire/snowflake": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz",
"integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==",
"license": "MIT",
"engines": {
"node": ">=v14.0.0",
"npm": ">=7.0.0"
@ -196,22 +344,28 @@
"integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA=="
},
"node_modules/@types/node": {
"version": "20.5.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.7.tgz",
"integrity": "sha512-dP7f3LdZIysZnmvP3ANJYTSwg+wLLl8p7RqniVlV7j+oXSXAbt9h0WIBFmJy5inWZoX9wZN6eXx+YXd9Rh3RBA=="
"version": "22.10.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.10.tgz",
"integrity": "sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.20.0"
}
},
"node_modules/@types/ws": {
"version": "8.5.5",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz",
"integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==",
"version": "8.5.9",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.9.tgz",
"integrity": "sha512-jbdrY0a8lxfdTp/+r7Z4CkycbOFN8WX+IOchLJr3juT/xzbJ8URyTVSJ/hvNdadTgM1mnedb47n+Y31GsFnQlg==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@vladfrangu/async_event_emitter": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz",
"integrity": "sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ==",
"version": "2.4.6",
"resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.6.tgz",
"integrity": "sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA==",
"license": "MIT",
"engines": {
"node": ">=v14.0.0",
"npm": ">=7.0.0"
@ -350,17 +504,6 @@
"node": ">=10.0.0"
}
},
"node_modules/busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"dependencies": {
"streamsearch": "^1.1.0"
},
"engines": {
"node": ">=10.16.0"
}
},
"node_modules/cacache": {
"version": "15.3.0",
"resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz",
@ -419,6 +562,7 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
"integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
"license": "MIT",
"engines": {
"node": ">=0.1.90"
}
@ -512,34 +656,48 @@
}
},
"node_modules/discord-api-types": {
"version": "0.37.50",
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.50.tgz",
"integrity": "sha512-X4CDiMnDbA3s3RaUXWXmgAIbY1uxab3fqe3qwzg5XutR3wjqi7M3IkgQbsIBzpqBN2YWr/Qdv7JrFRqSgb4TFg=="
"version": "0.37.61",
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.61.tgz",
"integrity": "sha512-o/dXNFfhBpYHpQFdT6FWzeO7pKc838QeeZ9d91CfVAtpr5XLK4B/zYxQbYgPdoMiTDvJfzcsLW5naXgmHGDNXw==",
"license": "MIT"
},
"node_modules/discord.js": {
"version": "14.13.0",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.13.0.tgz",
"integrity": "sha512-Kufdvg7fpyTEwANGy9x7i4od4yu5c6gVddGi5CKm4Y5a6sF0VBODObI3o0Bh7TGCj0LfNT8Qp8z04wnLFzgnbA==",
"version": "14.14.1",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.14.1.tgz",
"integrity": "sha512-/hUVzkIerxKHyRKopJy5xejp4MYKDPTszAnpYxzVVv4qJYf+Tkt+jnT2N29PIPschicaEEpXwF2ARrTYHYwQ5w==",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/builders": "^1.6.5",
"@discordjs/collection": "^1.5.3",
"@discordjs/formatters": "^0.3.2",
"@discordjs/rest": "^2.0.1",
"@discordjs/util": "^1.0.1",
"@discordjs/ws": "^1.0.1",
"@sapphire/snowflake": "^3.5.1",
"@types/ws": "^8.5.5",
"discord-api-types": "0.37.50",
"fast-deep-equal": "^3.1.3",
"lodash.snakecase": "^4.1.1",
"tslib": "^2.6.1",
"undici": "5.22.1",
"ws": "^8.13.0"
"@discordjs/builders": "^1.7.0",
"@discordjs/collection": "1.5.3",
"@discordjs/formatters": "^0.3.3",
"@discordjs/rest": "^2.1.0",
"@discordjs/util": "^1.0.2",
"@discordjs/ws": "^1.0.2",
"@sapphire/snowflake": "3.5.1",
"@types/ws": "8.5.9",
"discord-api-types": "0.37.61",
"fast-deep-equal": "3.1.3",
"lodash.snakecase": "4.1.1",
"tslib": "2.6.2",
"undici": "5.27.2",
"ws": "8.14.2"
},
"engines": {
"node": ">=16.11.0"
}
},
"node_modules/dotenv": {
"version": "16.4.7",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
"integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@ -583,7 +741,8 @@
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"license": "MIT"
},
"node_modules/follow-redirects": {
"version": "1.15.3",
@ -621,6 +780,7 @@
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/freepbx-graphql-client/-/freepbx-graphql-client-0.1.1.tgz",
"integrity": "sha512-JqDTlL0EA/bUMit9aODIupWSqF87WHWrCD6i716FzeOzS46cMFq/OajzftTMwOZQf20MMkJM2HI6CRnNlRGl6A==",
"license": "MIT",
"dependencies": {
"graphql": "^15.6.1",
"graphql-request": "^3.6.1"
@ -831,7 +991,8 @@
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
},
"node_modules/lodash.snakecase": {
"version": "4.1.1",
@ -850,9 +1011,10 @@
}
},
"node_modules/magic-bytes.js": {
"version": "1.0.15",
"resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.0.15.tgz",
"integrity": "sha512-bpRmwbRHqongRhA+mXzbLWjVy7ylqmfMBYaQkSs6pac0z6hBTvsgrH0r4FBYd/UYVJBmS6Rp/O+oCCQVLzKV1g=="
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.10.0.tgz",
"integrity": "sha512-/k20Lg2q8LE5xiaaSkMXk4sfvI+9EGEykFS4b0CHHGWqDYU0bGUFSwchNOMA56D7TCs9GwVTkqe9als1/ns8UQ==",
"license": "MIT"
},
"node_modules/make-dir": {
"version": "3.1.0",
@ -1444,14 +1606,6 @@
"node": ">= 8"
}
},
"node_modules/streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@ -1514,14 +1668,16 @@
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/ts-mixer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz",
"integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ=="
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz",
"integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==",
"license": "MIT"
},
"node_modules/tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
"license": "0BSD"
},
"node_modules/tweetnacl": {
"version": "0.14.5",
@ -1529,16 +1685,23 @@
"integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
},
"node_modules/undici": {
"version": "5.22.1",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz",
"integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==",
"version": "5.27.2",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.27.2.tgz",
"integrity": "sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==",
"license": "MIT",
"dependencies": {
"busboy": "^1.6.0"
"@fastify/busboy": "^2.0.0"
},
"engines": {
"node": ">=14.0"
}
},
"node_modules/undici-types": {
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"license": "MIT"
},
"node_modules/unique-filename": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
@ -1605,9 +1768,10 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"node_modules/ws": {
"version": "8.13.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
"version": "8.14.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz",
"integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},

View file

@ -12,6 +12,7 @@
"axios": "^1.6.0",
"colors": "^1.4.0",
"discord.js": "14.14.1",
"dotenv": "^16.4.7",
"freepbx-graphql-client": "^0.1.1",
"mariadb": "^3.2.0",
"ping": "^0.4.4",

View file

@ -1,6 +0,0 @@
[
{
"name": "Test",
"value": "700"
}
]