mirror of
https://github.com/NekoMonci12/RakunNakun-AI.git
synced 2026-01-04 15:31:44 +00:00
API System
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
// cacheManagerRedis.js
|
||||
|
||||
const { createClient } = require('redis');
|
||||
|
||||
class CacheManagerRedis {
|
||||
|
||||
17
database.js
17
database.js
@@ -60,6 +60,21 @@ class Database {
|
||||
);
|
||||
`;
|
||||
|
||||
// Create ApiKeys table
|
||||
const createApiKeysQuery = `
|
||||
CREATE TABLE IF NOT EXISTS ApiKeys (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
API_KEY VARCHAR(255) NOT NULL UNIQUE,
|
||||
GUILD_ID VARCHAR(255) NOT NULL,
|
||||
USER_ID TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_guild_id FOREIGN KEY (GUILD_ID) REFERENCES Guilds(GUILD_ID)
|
||||
ON UPDATE CASCADE
|
||||
ON DELETE SET NULL
|
||||
);
|
||||
`;
|
||||
|
||||
|
||||
try {
|
||||
await this.pool.query(createModelsQuery);
|
||||
console.log('Models table is ready or already exists.');
|
||||
@@ -67,6 +82,8 @@ class Database {
|
||||
console.log('Guilds table is ready or already exists.');
|
||||
await this.pool.query(createChatLogsQuery);
|
||||
console.log('ChatLogs table is ready or already exists.');
|
||||
await this.pool.query(createApiKeysQuery);
|
||||
console.log('ApiKeys table is ready or already exists.');
|
||||
} catch (error) {
|
||||
console.error('Error creating tables:', error);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// hybridCacheManager.js
|
||||
|
||||
const CacheManagerRedis = require('./cacheManagerRedis');
|
||||
const MongoCacheManager = require('./mongoCacheManager');
|
||||
|
||||
|
||||
522
index.js
522
index.js
@@ -1,319 +1,337 @@
|
||||
// index.js
|
||||
|
||||
require('dotenv').config();
|
||||
const express = require('express');
|
||||
const axios = require('axios');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
const { Client, GatewayIntentBits, SlashCommandBuilder } = require('discord.js');
|
||||
const Database = require('./database');
|
||||
const CommandDeployer = require('./deploy-commands');
|
||||
const axios = require('axios');
|
||||
const HybridCacheManager = require('./hybridCacheManager');
|
||||
const MessageSplitter = require('./messageSplitter');
|
||||
const PastebinClient = require('./pastebinClient');
|
||||
require('dotenv').config();
|
||||
|
||||
// Simple logging helpers
|
||||
// ——— Logging Helpers ———
|
||||
const logInfo = (msg, ...args) => console.log(`[INFO] ${msg}`, ...args);
|
||||
const logDebug = (msg, ...args) => console.log(`[DEBUG] ${msg}`, ...args);
|
||||
const logError = (msg, ...args) => console.error(`[ERROR] ${msg}`, ...args);
|
||||
|
||||
// Initialize PasteBin (pastebin method is left unchanged)
|
||||
const pastebinClient = new PastebinClient(process.env.PASTEBIN_DEV_KEY);
|
||||
// ——— Globals / Defaults ———
|
||||
const defaultModelId = 'deepseek-chat';
|
||||
const defaultPersona = 'You are a helpful assistant.';
|
||||
const defaultApiUrl = process.env.OPENAI_BASE_URL;
|
||||
const MIN_TOKEN_THRESH = 2000;
|
||||
|
||||
async function safeDeferReply(interaction) {
|
||||
try {
|
||||
if (!interaction.deferred && !interaction.replied) {
|
||||
await interaction.deferReply();
|
||||
}
|
||||
} catch (error) {
|
||||
logError("Error deferring reply:", error);
|
||||
}
|
||||
}
|
||||
// ——— Init Shared Resources ———
|
||||
const db = new Database();
|
||||
const cache = new HybridCacheManager(
|
||||
{ url: process.env.REDIS_URL },
|
||||
process.env.MONGO_URL,
|
||||
process.env.MONGO_DB_NAME
|
||||
);
|
||||
const splitter = new MessageSplitter(2000);
|
||||
const pastebin = new PastebinClient(process.env.PASTEBIN_DEV_KEY);
|
||||
|
||||
(async () => {
|
||||
// Initialize database (create tables if needed)
|
||||
const db = new Database();
|
||||
// 1️⃣ Database tables
|
||||
await db.init();
|
||||
logInfo("Database initialization complete.");
|
||||
logInfo('Database initialized.');
|
||||
|
||||
// Instantiate Hybrid Cache Manager and message splitter
|
||||
const redisOptions = { url: process.env.REDIS_URL || 'redis://localhost:6379' };
|
||||
const mongoUrl = process.env.MONGO_URL || 'mongodb://localhost:27017';
|
||||
const dbName = process.env.MONGO_DB_NAME || 'discordCache';
|
||||
const cache = new HybridCacheManager(redisOptions, mongoUrl, dbName);
|
||||
const splitter = new MessageSplitter(2000);
|
||||
|
||||
// Specify the default model ID and persona to use if none is set for a guild
|
||||
const defaultModelId = 'deepseek-chat';
|
||||
const defaultPersona = 'You are a helpful assistant.';
|
||||
const defaultApiUrl = process.env.OPENAI_BASE_URL;
|
||||
|
||||
// --- Define Slash Command ---
|
||||
// 2️⃣ Deploy Discord Slash Commands
|
||||
const commands = [
|
||||
new SlashCommandBuilder()
|
||||
.setName('chat')
|
||||
.setDescription('Chat with the RakunNakun')
|
||||
.addStringOption(option =>
|
||||
option.setName('message')
|
||||
.setDescription('Your question to RakunNakun')
|
||||
.setRequired(true)
|
||||
)
|
||||
].map(command => command.toJSON());
|
||||
.addStringOption(o => o.setName('message').setDescription('Your question').setRequired(true)),
|
||||
|
||||
// --- Deploy Commands using CommandDeployer class ---
|
||||
const deployer = new CommandDeployer(commands, process.env.CLIENT_ID, process.env.DISCORD_TOKEN);
|
||||
await deployer.deploy();
|
||||
logInfo("Slash commands deployed.");
|
||||
new SlashCommandBuilder()
|
||||
.setName('generate-api')
|
||||
.setDescription('Generate a new API key for this guild'),
|
||||
|
||||
// Create a new Discord client with the required intents
|
||||
const client = new Client({
|
||||
intents: [GatewayIntentBits.Guilds]
|
||||
});
|
||||
new SlashCommandBuilder()
|
||||
.setName('list-api')
|
||||
.setDescription('List all API keys for this guild'),
|
||||
|
||||
client.once('ready', () => {
|
||||
logInfo(`Logged in as ${client.user.tag}`);
|
||||
});
|
||||
new SlashCommandBuilder()
|
||||
.setName('delete-api')
|
||||
.setDescription('Delete an API key')
|
||||
.addStringOption(o => o.setName('key').setDescription('API key to delete').setRequired(true))
|
||||
].map(c => c.toJSON());
|
||||
|
||||
// Listen for slash command interactions
|
||||
client.on('interactionCreate', async (interaction) => {
|
||||
await new CommandDeployer(commands, process.env.CLIENT_ID, process.env.DISCORD_TOKEN).deploy();
|
||||
logInfo('Slash commands deployed.');
|
||||
|
||||
// 3️⃣ Start Discord Bot
|
||||
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
|
||||
client.once('ready', () => logInfo(`Logged in as ${client.user.tag}`));
|
||||
client.on('interactionCreate', async interaction => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
if (interaction.commandName !== 'chat') return;
|
||||
|
||||
const userMessage = interaction.options.getString('message');
|
||||
logInfo(`Received message: "${userMessage}" from ${interaction.user.tag}`);
|
||||
const { commandName, guildId, user, options } = interaction;
|
||||
|
||||
// Set default factors and values
|
||||
// Only run permission check for certain commands
|
||||
const commandsRequiringOwnership = ['generate-api', 'list-api', 'delete-api'];
|
||||
if (commandsRequiringOwnership.includes(commandName)) {
|
||||
const [guildRows] = await db.pool.query(
|
||||
'SELECT GUILD_OWNER_ID FROM Guilds WHERE GUILD_ID = ?',
|
||||
[guildId]
|
||||
);
|
||||
|
||||
if (!guildRows.length || guildRows[0].GUILD_OWNER_ID !== user.id) {
|
||||
return await interaction.reply({
|
||||
content: '❌ You do not have permission to use this command. Only the guild owner can use this command.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Handle /chat
|
||||
if (commandName === 'chat') {
|
||||
const userMessage = options.getString('message');
|
||||
logInfo(`[/chat] ${user.tag}: ${userMessage}`);
|
||||
|
||||
try {
|
||||
if (!interaction.deferred && !interaction.replied) {
|
||||
await interaction.deferReply();
|
||||
}
|
||||
} catch (err) {
|
||||
logError('Defer error:', err);
|
||||
}
|
||||
|
||||
const { reply, tokensUsed } = await processMessage({
|
||||
message: userMessage,
|
||||
authKey: user.id,
|
||||
isDiscord: true,
|
||||
guildId,
|
||||
userId: user.id
|
||||
});
|
||||
|
||||
if (reply) {
|
||||
const parts = splitter.split(reply);
|
||||
await interaction.editReply(parts.shift());
|
||||
for (const part of parts) await interaction.followUp(part);
|
||||
} else {
|
||||
await interaction.editReply('❌ Failed to get a response.');
|
||||
}
|
||||
}
|
||||
|
||||
// Handle /generate-api
|
||||
else if (commandName === 'generate-api') {
|
||||
const apiKey = uuidv4();
|
||||
await db.pool.query(
|
||||
'INSERT INTO ApiKeys (API_KEY, GUILD_ID, USER_ID) VALUES (?, ?, ?)',
|
||||
[apiKey, guildId, user.id]
|
||||
);
|
||||
|
||||
await interaction.reply({
|
||||
content: `✅ API key generated: \`${apiKey}\``,
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
// Handle /list-api
|
||||
else if (commandName === 'list-api') {
|
||||
const [rows] = await db.pool.query(
|
||||
'SELECT API_KEY, USER_ID FROM ApiKeys WHERE GUILD_ID = ?',
|
||||
[guildId]
|
||||
);
|
||||
|
||||
if (!rows.length) {
|
||||
return await interaction.reply({
|
||||
content: 'ℹ️ No API keys found for this server.',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
const keyList = rows.map(row => `• \`${row.API_KEY}\` → <@${row.USER_ID}>`).join('\n');
|
||||
await interaction.reply({
|
||||
content: `🔑 API keys for this guild:\n${keyList}`,
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
|
||||
// Handle /delete-api
|
||||
else if (commandName === 'delete-api') {
|
||||
const apiKey = options.getString('key');
|
||||
|
||||
const [rows] = await db.pool.query(
|
||||
'DELETE FROM ApiKeys WHERE API_KEY = ? AND GUILD_ID = ?',
|
||||
[apiKey, guildId]
|
||||
);
|
||||
|
||||
await interaction.reply({
|
||||
content: '🗑️ API key deleted (if it existed).',
|
||||
ephemeral: true
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
client.login(process.env.DISCORD_TOKEN);
|
||||
|
||||
// 4️⃣ Expose Express API
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
|
||||
app.post('/process-message', async (req, res) => {
|
||||
const { message, apiKey: authKey } = req.body;
|
||||
if (!message) {
|
||||
return res.status(400).json({ error: 'Missing message' });
|
||||
}
|
||||
if (!authKey) {
|
||||
return res.status(400).json({ error: 'Missing API key' });
|
||||
}
|
||||
|
||||
logInfo(`[/process-message] authKey=${authKey} message="${message}"`);
|
||||
|
||||
try {
|
||||
const { reply, tokensUsed, error } = await processMessage({ message, authKey });
|
||||
if (error) return res.status(400).json({ error });
|
||||
return res.json({ reply, tokensUsed });
|
||||
} catch (err) {
|
||||
logError('Unhandled error in /process-message:', err);
|
||||
return res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
const PORT = process.env.API_PORT || 3000;
|
||||
app.listen(PORT, () => logInfo(`API server listening on http://localhost:${PORT}`));
|
||||
})();
|
||||
|
||||
// ——— Shared Discord Function ———
|
||||
async function isGuildOwner(guildId, userId) {
|
||||
const [rows] = await db.pool.query(
|
||||
'SELECT GUILD_OWNER_ID FROM Guilds WHERE GUILD_ID = ?',
|
||||
[guildId]
|
||||
);
|
||||
if (!rows.length) return false;
|
||||
return rows[0].GUILD_OWNER_ID === userId;
|
||||
}
|
||||
|
||||
// ——— Shared Processing Function ———
|
||||
async function processMessage({
|
||||
message,
|
||||
authKey,
|
||||
isDiscord = false, // if true, we return { reply, tokensUsed } else { reply, tokensUsed, error }
|
||||
guildId: overrideGuildId = null,
|
||||
userId: overrideUserId = null,
|
||||
}) {
|
||||
// 1️⃣ Authenticate
|
||||
let guildId = overrideGuildId;
|
||||
if (!guildId) {
|
||||
const [apiKeyRows] = await db.pool.query('SELECT GUILD_ID FROM ApiKeys WHERE API_KEY = ?', [authKey]);
|
||||
if (!apiKeyRows.length) return { error: 'Invalid API key' };
|
||||
guildId = apiKeyRows[0].GUILD_ID;
|
||||
}
|
||||
const userId = overrideUserId || authKey;
|
||||
|
||||
// 2️⃣ Load guild settings
|
||||
const [guildRows] = await db.pool.query(
|
||||
'SELECT CHAT_MODELS, CHAT_TOKENS, DEBUG, CHAT_PERSONA FROM Guilds WHERE GUILD_ID = ?',
|
||||
[guildId]
|
||||
);
|
||||
if (!guildRows.length) return { error: 'Guild not registered' };
|
||||
let { CHAT_MODELS, CHAT_TOKENS, DEBUG, CHAT_PERSONA } = guildRows[0];
|
||||
let currentTokens = Number(CHAT_TOKENS) || 0;
|
||||
if (currentTokens < MIN_TOKEN_THRESH) return { error: 'Insufficient tokens' };
|
||||
|
||||
let modelIdToUse = CHAT_MODELS || defaultModelId;
|
||||
let personaToUse = CHAT_PERSONA || defaultPersona;
|
||||
let debugMode = DEBUG === 1;
|
||||
let finalReply = null;
|
||||
|
||||
// 3️⃣ Load model params
|
||||
let tokenInputFactor = 0.6;
|
||||
let tokenOutputFactor = 0.9;
|
||||
let tokenCachedInputFactor = 0.6;
|
||||
let tokenCachedOutputFactor = 0.9;
|
||||
let tokenCachedInFactor = 0.6;
|
||||
let tokenCachedOutFactor= 0.9;
|
||||
let modelApiKey = process.env.OPENAI_API_KEY;
|
||||
let modelBaseUrl = process.env.OPENAI_BASE_URL;
|
||||
let modelIdToUse = defaultModelId;
|
||||
let personaToUse = defaultPersona;
|
||||
let requiredRoleId = null;
|
||||
let debugMode = false;
|
||||
let currentTokens = 0;
|
||||
let pasteUrl;
|
||||
let modelBaseUrl = defaultApiUrl;
|
||||
|
||||
try {
|
||||
// Fetch guild settings including model, token balance, persona, etc.
|
||||
if (interaction.guild && interaction.guild.id) {
|
||||
const [guildRows] = await db.pool.query(
|
||||
'SELECT CHAT_MODELS, GUILD_USERS_ID, GUILD_OWNER_ID, DEBUG, CHAT_TOKENS, CHAT_PERSONA FROM Guilds WHERE GUILD_ID = ?',
|
||||
[interaction.guild.id]
|
||||
);
|
||||
if (guildRows.length === 0) {
|
||||
logError("Guild not registered:", interaction.guild.id);
|
||||
await interaction.reply(`Your guild is not registered in our system. Please contact the guild owner <@${interaction.guild.ownerId}>.`);
|
||||
return;
|
||||
}
|
||||
currentTokens = Number(guildRows[0].CHAT_TOKENS) || 0;
|
||||
logDebug(`Current token balance: ${currentTokens}`);
|
||||
if (currentTokens < 2000) {
|
||||
logInfo(`Token balance (${currentTokens}) is below threshold for guild ${interaction.guild.id}.`);
|
||||
await interaction.reply("Insufficient tokens in your guild. Please recharge tokens.");
|
||||
return;
|
||||
}
|
||||
if (guildRows[0].CHAT_MODELS) {
|
||||
modelIdToUse = guildRows[0].CHAT_MODELS;
|
||||
logInfo(`Guild ${interaction.guild.id} is using model ${modelIdToUse}`);
|
||||
} else {
|
||||
logInfo(`Guild ${interaction.guild.id} has no custom model. Using default model.`);
|
||||
}
|
||||
if (guildRows[0].GUILD_USERS_ID) {
|
||||
requiredRoleId = guildRows[0].GUILD_USERS_ID;
|
||||
}
|
||||
if (guildRows[0].CHAT_PERSONA) {
|
||||
personaToUse = guildRows[0].CHAT_PERSONA;
|
||||
}
|
||||
if (guildRows[0].DEBUG && Number(guildRows[0].DEBUG) === 1) {
|
||||
debugMode = true;
|
||||
logDebug("Debug mode enabled for this guild.");
|
||||
}
|
||||
}
|
||||
|
||||
// Check required role if defined.
|
||||
if (requiredRoleId && !interaction.member.roles.cache.has(requiredRoleId)) {
|
||||
logInfo(`User ${interaction.user.tag} lacks the required role (${requiredRoleId}).`);
|
||||
await interaction.reply("You don't have the required role to use this command.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Query the Models table for the model parameters using modelIdToUse
|
||||
const [modelRows] = await db.pool.query(
|
||||
'SELECT TOKEN_INPUT, TOKEN_OUTPUT, TOKEN_CACHED_INPUT, TOKEN_CACHED_OUTPUT, API_KEY, API_URL FROM Models WHERE MODEL_ID = ?',
|
||||
[modelIdToUse]
|
||||
`SELECT TOKEN_INPUT, TOKEN_OUTPUT, TOKEN_CACHED_INPUT, TOKEN_CACHED_OUTPUT, API_KEY, API_URL
|
||||
FROM Models WHERE MODEL_ID = ?`, [modelIdToUse]
|
||||
);
|
||||
if (modelRows.length > 0) {
|
||||
tokenInputFactor = modelRows[0].TOKEN_INPUT || tokenInputFactor;
|
||||
tokenOutputFactor = modelRows[0].TOKEN_OUTPUT || tokenOutputFactor;
|
||||
tokenCachedInputFactor = modelRows[0].TOKEN_CACHED_INPUT || tokenInputFactor;
|
||||
tokenCachedOutputFactor = modelRows[0].TOKEN_CACHED_OUTPUT || tokenOutputFactor;
|
||||
if (modelRows[0].API_KEY) {
|
||||
modelApiKey = modelRows[0].API_KEY;
|
||||
}
|
||||
if (modelRows[0].API_URL) {
|
||||
modelBaseUrl = modelRows[0].API_URL;
|
||||
}
|
||||
if (debugMode) {
|
||||
logDebug("Model row:", modelRows[0]);
|
||||
}
|
||||
} else {
|
||||
logError(`No record found in Models for ${modelIdToUse}. Using default parameters.`);
|
||||
}
|
||||
} catch (error) {
|
||||
logError('Error fetching model parameters:', error);
|
||||
if (modelRows.length) {
|
||||
const m = modelRows[0];
|
||||
tokenInputFactor = m.TOKEN_INPUT ?? tokenInputFactor;
|
||||
tokenOutputFactor = m.TOKEN_OUTPUT ?? tokenOutputFactor;
|
||||
tokenCachedInFactor = m.TOKEN_CACHED_INPUT ?? tokenCachedInFactor;
|
||||
tokenCachedOutFactor = m.TOKEN_CACHED_OUTPUT?? tokenCachedOutFactor;
|
||||
modelApiKey = m.API_KEY || modelApiKey;
|
||||
modelBaseUrl = m.API_URL || modelBaseUrl;
|
||||
}
|
||||
|
||||
// --- Helper Functions to Count Tokens using dynamic factors ---
|
||||
const calculateInputTokens = (text, factor = tokenInputFactor) => Math.ceil(text.length * factor);
|
||||
|
||||
// Check cache before making an API call
|
||||
const cachedOutput = await cache.getCachedResult(userMessage);
|
||||
if (cachedOutput) {
|
||||
logDebug("Cache hit: Using cached result for input:", userMessage);
|
||||
const cachedInputTokens = Math.ceil(userMessage.length * tokenCachedInputFactor);
|
||||
const cachedOutputTokens = Math.ceil(cachedOutput.length * tokenCachedOutputFactor);
|
||||
let finalReply = cachedOutput;
|
||||
if (debugMode) {
|
||||
finalReply += `\n\n**Token Usage (Cached):**\n- Input Tokens: ${cachedInputTokens}\n- Output Tokens: ${cachedOutputTokens}`;
|
||||
}
|
||||
try {
|
||||
pasteUrl = await pastebinClient.createPaste(finalReply, '1M', 'Chat Log (Cached)');
|
||||
if (debugMode) {
|
||||
logInfo(`Chat logged on Pastebin: ${pasteUrl}`);
|
||||
}
|
||||
} catch (pasteError) {
|
||||
if (debugMode) {
|
||||
logError('Failed to create Pastebin paste:', pasteError);
|
||||
}
|
||||
pasteUrl = "FAILED ERROR CODE";
|
||||
}
|
||||
// 4️⃣ Cache lookup
|
||||
const cached = await cache.getCachedResult(message);
|
||||
if (cached) {
|
||||
const inT = Math.ceil(message.length * tokenCachedInFactor);
|
||||
const outT = Math.ceil(cached.length * tokenCachedOutFactor);
|
||||
await db.pool.query(
|
||||
'INSERT INTO ChatLogs (GUILD_ID, GUILD_USERS_ID, MESSAGE_INPUT, MESSAGE_OUTPUT, CACHED) VALUES (?, ?, ?, ?, 1)',
|
||||
[interaction.guild.id, interaction.user.id, userMessage, pasteUrl]
|
||||
[guildId, userId, message, 'CACHED']
|
||||
);
|
||||
const parts = splitter.split(finalReply);
|
||||
if (parts.length === 1) {
|
||||
await interaction.reply(parts[0]);
|
||||
} else {
|
||||
await interaction.reply(parts[0]);
|
||||
for (let i = 1; i < parts.length; i++) {
|
||||
await interaction.followUp(parts[i]);
|
||||
}
|
||||
}
|
||||
const tokensUsed = cachedInputTokens + cachedOutputTokens;
|
||||
await db.pool.query(
|
||||
'UPDATE Guilds SET CHAT_TOKENS = CHAT_TOKENS - ? WHERE GUILD_ID = ?',
|
||||
[tokensUsed, interaction.guild.id]
|
||||
[inT + outT, guildId]
|
||||
);
|
||||
logInfo(`Deducted ${tokensUsed} tokens (cached). New balance: ${currentTokens - tokensUsed}`);
|
||||
return;
|
||||
} else {
|
||||
logDebug("Cache miss: No cached result for input:", userMessage);
|
||||
finalReply = cached;
|
||||
if (debugMode) {
|
||||
finalReply += `
|
||||
------------------------------
|
||||
**[DEBUG INFO]**
|
||||
• Mode: CACHED
|
||||
• Model ID: ${modelIdToUse}
|
||||
• Input Tokens: ${inT}
|
||||
• Output Tokens: ${outT}
|
||||
• Total Tokens Used: ${inT + outT}`;
|
||||
}
|
||||
return { reply: finalReply, tokensUsed: inT + outT };
|
||||
}
|
||||
|
||||
// Defer reply to allow time for API processing
|
||||
await safeDeferReply(interaction);
|
||||
|
||||
try {
|
||||
logDebug("Sending API request with model:", modelIdToUse);
|
||||
let axiosResponse;
|
||||
try {
|
||||
axiosResponse = await axios.post(
|
||||
// 5️⃣ API call
|
||||
const apiRes = await axios.post(
|
||||
modelBaseUrl,
|
||||
{
|
||||
model: modelIdToUse,
|
||||
messages: [
|
||||
{ role: 'system', content: personaToUse },
|
||||
{ role: 'user', content: userMessage }
|
||||
{ role: 'user', content: message }
|
||||
],
|
||||
stream: false
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Authorization': `Bearer ${modelApiKey}`,
|
||||
Authorization: `Bearer ${modelApiKey}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
if (
|
||||
error.response &&
|
||||
error.response.data &&
|
||||
error.response.data.error &&
|
||||
error.response.data.error.message &&
|
||||
error.response.data.error.message.includes('Service is too busy')
|
||||
) {
|
||||
logInfo("Primary API is too busy. Falling back to default model and default API.");
|
||||
axiosResponse = await axios.post(
|
||||
defaultApiUrl,
|
||||
{
|
||||
model: defaultModelId,
|
||||
messages: [
|
||||
{ role: 'system', content: personaToUse },
|
||||
{ role: 'user', content: userMessage }
|
||||
],
|
||||
stream: false
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
logDebug("API response received.");
|
||||
const reply = axiosResponse.data.choices[0].message.content.trim();
|
||||
const outputTokens = Math.ceil(reply.length * tokenOutputFactor);
|
||||
const apiInputTokens = calculateInputTokens(userMessage);
|
||||
await cache.setCache(userMessage, reply);
|
||||
logDebug("Caching API response for input:", userMessage);
|
||||
|
||||
let finalReply = reply;
|
||||
const reply = apiRes.data.choices[0].message.content.trim();
|
||||
const inT = Math.ceil(message.length * tokenInputFactor);
|
||||
const outT = Math.ceil(reply.length * tokenOutputFactor);
|
||||
const tokensUsed = inT + outT;
|
||||
finalReply = reply;
|
||||
if (debugMode) {
|
||||
finalReply += `\n\n**Token Usage:**\n- Model-ID: \`${modelIdToUse}\`\n- Input Tokens: ${apiInputTokens}\n- Output Tokens: ${outputTokens}`;
|
||||
}
|
||||
|
||||
try {
|
||||
pasteUrl = await pastebinClient.createPaste(finalReply, '1M', 'Chat Log');
|
||||
if (debugMode) {
|
||||
logInfo(`Chat logged on Pastebin: ${pasteUrl}`);
|
||||
}
|
||||
} catch (pasteError) {
|
||||
if (debugMode) {
|
||||
logError('Failed to create Pastebin paste:', pasteError);
|
||||
}
|
||||
pasteUrl = "FAILED ERROR CODE";
|
||||
finalReply += `
|
||||
------------------------------
|
||||
**[DEBUG INFO]**
|
||||
• Mode: REQUEST
|
||||
• Model ID: ${modelIdToUse}
|
||||
• Input Tokens: ${inT}
|
||||
• Output Tokens: ${outT}
|
||||
• Total Tokens Used: ${inT + outT}`;
|
||||
}
|
||||
|
||||
// cache & log
|
||||
await cache.setCache(message, reply);
|
||||
await db.pool.query(
|
||||
'INSERT INTO ChatLogs (GUILD_ID, GUILD_USERS_ID, MESSAGE_INPUT, MESSAGE_OUTPUT, CACHED) VALUES (?, ?, ?, ?, 0)',
|
||||
[interaction.guild.id, interaction.user.id, userMessage, pasteUrl]
|
||||
[guildId, userId, message, 'COMING SOON']
|
||||
);
|
||||
|
||||
const parts = splitter.split(finalReply);
|
||||
if (parts.length === 1) {
|
||||
await interaction.editReply(parts[0]);
|
||||
} else {
|
||||
await interaction.editReply(parts[0]);
|
||||
for (let i = 1; i < parts.length; i++) {
|
||||
await interaction.followUp(parts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
const tokensUsed = apiInputTokens + outputTokens;
|
||||
await db.pool.query(
|
||||
'UPDATE Guilds SET CHAT_TOKENS = CHAT_TOKENS - ? WHERE GUILD_ID = ?',
|
||||
[tokensUsed, interaction.guild.id]
|
||||
[tokensUsed, guildId]
|
||||
);
|
||||
logInfo(`Deducted ${tokensUsed} tokens (API). New balance: ${currentTokens - tokensUsed}`);
|
||||
} catch (error) {
|
||||
logError('Error with API:', error.response ? error.response.data : error.message);
|
||||
await interaction.editReply('There was an error processing your request.');
|
||||
}
|
||||
});
|
||||
|
||||
client.login(process.env.DISCORD_TOKEN);
|
||||
})();
|
||||
return { reply: finalReply, tokensUsed };
|
||||
}
|
||||
|
||||
586
package-lock.json
generated
586
package-lock.json
generated
@@ -8,11 +8,13 @@
|
||||
"axios": "^1.4.0",
|
||||
"discord.js": "^14.11.0",
|
||||
"dotenv": "^16.0.0",
|
||||
"express": "^4.18.2",
|
||||
"mongodb": "^5.7.0",
|
||||
"mysql2": "^3.2.0",
|
||||
"openai": "^3.2.1",
|
||||
"qs": "^6.11.2",
|
||||
"redis": "^4.6.7"
|
||||
"redis": "^4.6.7",
|
||||
"uuid": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@discordjs/builders": {
|
||||
@@ -288,6 +290,25 @@
|
||||
"npm": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-types": "~2.1.34",
|
||||
"negotiator": "0.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
@@ -314,6 +335,57 @@
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.3",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.5",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.13.0",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8",
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser/node_modules/iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser/node_modules/qs": {
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/bson": {
|
||||
"version": "5.5.1",
|
||||
"resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz",
|
||||
@@ -323,6 +395,15 @@
|
||||
"node": ">=14.20.1"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
@@ -373,6 +454,51 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "5.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/content-type": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
|
||||
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
|
||||
"integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie-signature": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
@@ -391,6 +517,25 @@
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/destroy": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
|
||||
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8",
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/discord-api-types": {
|
||||
"version": "0.37.119",
|
||||
"resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.119.tgz",
|
||||
@@ -449,6 +594,21 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
|
||||
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
@@ -494,12 +654,106 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-html": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/etag": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "4.21.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
|
||||
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.20.3",
|
||||
"content-disposition": "0.5.4",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.7.1",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"finalhandler": "1.3.1",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"merge-descriptors": "1.0.3",
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.12",
|
||||
"proxy-addr": "~2.0.7",
|
||||
"qs": "6.13.0",
|
||||
"range-parser": "~1.2.1",
|
||||
"safe-buffer": "5.2.1",
|
||||
"send": "0.19.0",
|
||||
"serve-static": "1.16.2",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "2.0.1",
|
||||
"type-is": "~1.6.18",
|
||||
"utils-merge": "1.0.1",
|
||||
"vary": "~1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/qs": {
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/finalhandler": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
|
||||
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"statuses": "2.0.1",
|
||||
"unpipe": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
@@ -535,6 +789,24 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/fresh": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
@@ -650,6 +922,22 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/http-errors": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
|
||||
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"depd": "2.0.0",
|
||||
"inherits": "2.0.4",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "2.0.1",
|
||||
"toidentifier": "1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
@@ -662,6 +950,12 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ip-address": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
|
||||
@@ -675,6 +969,15 @@
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/is-property": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
|
||||
@@ -744,6 +1047,15 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/memory-pager": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
|
||||
@@ -751,6 +1063,36 @@
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/merge-descriptors": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
|
||||
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/methods": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mime": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
@@ -823,6 +1165,12 @@
|
||||
"whatwg-url": "^11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mysql2": {
|
||||
"version": "3.12.0",
|
||||
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.12.0.tgz",
|
||||
@@ -855,6 +1203,15 @@
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/negotiator": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.13.4",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
||||
@@ -867,6 +1224,18 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/on-finished": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
||||
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ee-first": "1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/openai": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/openai/-/openai-3.3.0.tgz",
|
||||
@@ -886,6 +1255,34 @@
|
||||
"follow-redirects": "^1.14.8"
|
||||
}
|
||||
},
|
||||
"node_modules/parseurl": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
||||
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"forwarded": "0.2.0",
|
||||
"ipaddr.js": "1.9.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
@@ -916,6 +1313,42 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/range-parser": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/raw-body": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
|
||||
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/raw-body/node_modules/iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/redis": {
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmjs.org/redis/-/redis-4.7.0.tgz",
|
||||
@@ -933,17 +1366,97 @@
|
||||
"@redis/time-series": "1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "0.19.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
|
||||
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"mime": "1.6.0",
|
||||
"ms": "2.1.3",
|
||||
"on-finished": "2.4.1",
|
||||
"range-parser": "~1.2.1",
|
||||
"statuses": "2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/seq-queue": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
|
||||
"integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="
|
||||
},
|
||||
"node_modules/serve-static": {
|
||||
"version": "1.16.2",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
|
||||
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"parseurl": "~1.3.3",
|
||||
"send": "0.19.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
|
||||
@@ -1065,6 +1578,24 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/statuses": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/toidentifier": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
|
||||
@@ -1089,6 +1620,19 @@
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/type-is": {
|
||||
"version": "1.6.18",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"media-typer": "0.3.0",
|
||||
"mime-types": "~2.1.24"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "6.21.1",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.21.1.tgz",
|
||||
@@ -1104,6 +1648,46 @@
|
||||
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/utils-merge": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"express": "^4.18.2",
|
||||
"discord.js": "^14.11.0",
|
||||
"dotenv": "^16.0.0",
|
||||
"mysql2": "^3.2.0",
|
||||
@@ -7,6 +8,7 @@
|
||||
"axios": "^1.4.0",
|
||||
"qs": "^6.11.2",
|
||||
"redis": "^4.6.7",
|
||||
"mongodb": "^5.7.0"
|
||||
"mongodb": "^5.7.0",
|
||||
"uuid": "^9.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// pastebinClient.js
|
||||
|
||||
const axios = require('axios');
|
||||
const qs = require('qs'); // for form URL-encoded data
|
||||
|
||||
|
||||
Reference in New Issue
Block a user