mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-28 12:44:28 +00:00
🖍️ refactor: Typed Console Colors and Hardened Script Helpers (#14778)
* 🛠️ refactor: Enhance console color handling and improve deleteNodeModules function
* refactor: Use coloredConsole for consistent console output in invite-user.js
* refactor: Convert year to string format in invite user payload
This commit is contained in:
parent
8f1f961212
commit
3a3a8dcad0
3 changed files with 49 additions and 32 deletions
|
|
@ -7,6 +7,12 @@ const path = require('path');
|
|||
const readline = require('readline');
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
/** @typedef {(message: string) => void} ConsoleColor */
|
||||
/** @typedef {{ orange: ConsoleColor, green: ConsoleColor, red: ConsoleColor, blue: ConsoleColor, purple: ConsoleColor, cyan: ConsoleColor, yellow: ConsoleColor, white: ConsoleColor, gray: ConsoleColor }} ColoredConsole */
|
||||
|
||||
const coloredConsole = /** @type {Console & ColoredConsole} */ (console);
|
||||
|
||||
/** @param {string} query @returns {Promise<string>} */
|
||||
const askQuestion = (query) => {
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
|
|
@ -21,16 +27,18 @@ const askQuestion = (query) => {
|
|||
);
|
||||
};
|
||||
|
||||
/** @param {string} query @returns {Promise<string>} */
|
||||
const askMultiLineQuestion = (query) => {
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
console.cyan(query);
|
||||
coloredConsole.cyan(query);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
let lines = [];
|
||||
/** @type {string[]} */
|
||||
const lines = [];
|
||||
rl.on('line', (line) => {
|
||||
if (line.trim() === '.') {
|
||||
rl.close();
|
||||
|
|
@ -46,16 +54,22 @@ function isDockerRunning() {
|
|||
try {
|
||||
execSync('docker info');
|
||||
return true;
|
||||
} catch (e) {
|
||||
} catch (_error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively removes a directory's node_modules.
|
||||
* Retries on transient ENOTEMPTY/EBUSY errors that fs.rmSync intermittently
|
||||
* throws on macOS (APFS) and Windows when entries are removed concurrently.
|
||||
*/
|
||||
/** @param {string} dir */
|
||||
function deleteNodeModules(dir) {
|
||||
const nodeModulesPath = path.join(dir, 'node_modules');
|
||||
if (fs.existsSync(nodeModulesPath)) {
|
||||
console.purple(`Deleting node_modules in ${dir}`);
|
||||
fs.rmSync(nodeModulesPath, { recursive: true });
|
||||
coloredConsole.purple(`Deleting node_modules in ${dir}`);
|
||||
fs.rmSync(nodeModulesPath, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,15 +79,15 @@ const silentExit = (code = 0) => {
|
|||
};
|
||||
|
||||
// Set the console colours
|
||||
console.orange = (msg) => console.log('\x1b[33m%s\x1b[0m', msg);
|
||||
console.green = (msg) => console.log('\x1b[32m%s\x1b[0m', msg);
|
||||
console.red = (msg) => console.log('\x1b[31m%s\x1b[0m', msg);
|
||||
console.blue = (msg) => console.log('\x1b[34m%s\x1b[0m', msg);
|
||||
console.purple = (msg) => console.log('\x1b[35m%s\x1b[0m', msg);
|
||||
console.cyan = (msg) => console.log('\x1b[36m%s\x1b[0m', msg);
|
||||
console.yellow = (msg) => console.log('\x1b[33m%s\x1b[0m', msg);
|
||||
console.white = (msg) => console.log('\x1b[37m%s\x1b[0m', msg);
|
||||
console.gray = (msg) => console.log('\x1b[90m%s\x1b[0m', msg);
|
||||
coloredConsole.orange = (/** @type {string} */ msg) => console.log('\x1b[33m%s\x1b[0m', msg);
|
||||
coloredConsole.green = (/** @type {string} */ msg) => console.log('\x1b[32m%s\x1b[0m', msg);
|
||||
coloredConsole.red = (/** @type {string} */ msg) => console.log('\x1b[31m%s\x1b[0m', msg);
|
||||
coloredConsole.blue = (/** @type {string} */ msg) => console.log('\x1b[34m%s\x1b[0m', msg);
|
||||
coloredConsole.purple = (/** @type {string} */ msg) => console.log('\x1b[35m%s\x1b[0m', msg);
|
||||
coloredConsole.cyan = (/** @type {string} */ msg) => console.log('\x1b[36m%s\x1b[0m', msg);
|
||||
coloredConsole.yellow = (/** @type {string} */ msg) => console.log('\x1b[33m%s\x1b[0m', msg);
|
||||
coloredConsole.white = (/** @type {string} */ msg) => console.log('\x1b[37m%s\x1b[0m', msg);
|
||||
coloredConsole.gray = (/** @type {string} */ msg) => console.log('\x1b[90m%s\x1b[0m', msg);
|
||||
|
||||
module.exports = {
|
||||
askQuestion,
|
||||
|
|
@ -81,4 +95,5 @@ module.exports = {
|
|||
silentExit,
|
||||
isDockerRunning,
|
||||
deleteNodeModules,
|
||||
coloredConsole,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,27 +3,29 @@ const mongoose = require('mongoose');
|
|||
const { checkEmailConfig, createInvite } = require('@librechat/api');
|
||||
const { User } = require('@librechat/data-schemas').createModels(mongoose);
|
||||
require('module-alias')({ base: path.resolve(__dirname, '..', 'api') });
|
||||
const { askQuestion, silentExit } = require('./helpers');
|
||||
const { createToken, findToken } = require('~/models');
|
||||
const { sendEmail } = require('~/server/utils');
|
||||
const { askQuestion, silentExit, coloredConsole } = require('./helpers');
|
||||
const { createToken, findToken } = require('../api/models');
|
||||
const { sendEmail } = require('../api/server/utils');
|
||||
const connect = require('./connect');
|
||||
|
||||
(async () => {
|
||||
await connect();
|
||||
|
||||
console.purple('--------------------------');
|
||||
console.purple('Invite a new user account!');
|
||||
console.purple('--------------------------');
|
||||
coloredConsole.purple('--------------------------');
|
||||
coloredConsole.purple('Invite a new user account!');
|
||||
coloredConsole.purple('--------------------------');
|
||||
|
||||
if (process.argv.length < 5) {
|
||||
console.orange('Usage: npm run invite-user <email>');
|
||||
console.orange('Note: if you do not pass in the arguments, you will be prompted for them.');
|
||||
console.purple('--------------------------');
|
||||
coloredConsole.orange('Usage: npm run invite-user <email>');
|
||||
coloredConsole.orange(
|
||||
'Note: if you do not pass in the arguments, you will be prompted for them.',
|
||||
);
|
||||
coloredConsole.purple('--------------------------');
|
||||
}
|
||||
|
||||
// Check if email service is enabled
|
||||
if (!checkEmailConfig()) {
|
||||
console.red('Error: Email service is not enabled!');
|
||||
coloredConsole.red('Error: Email service is not enabled!');
|
||||
silentExit(1);
|
||||
}
|
||||
|
||||
|
|
@ -40,20 +42,20 @@ const connect = require('./connect');
|
|||
email = email.trim().toLowerCase();
|
||||
// Validate the email
|
||||
if (!email.includes('@')) {
|
||||
console.red('Error: Invalid email address!');
|
||||
coloredConsole.red('Error: Invalid email address!');
|
||||
silentExit(1);
|
||||
}
|
||||
|
||||
// Check if the user already exists
|
||||
const userExists = await User.findOne({ email });
|
||||
if (userExists) {
|
||||
console.red('Error: A user with that email already exists!');
|
||||
coloredConsole.red('Error: A user with that email already exists!');
|
||||
silentExit(1);
|
||||
}
|
||||
|
||||
const token = await createInvite(email, { createToken, findToken });
|
||||
if (typeof token !== 'string') {
|
||||
console.red('Error: Failed to create the invite token!');
|
||||
coloredConsole.red('Error: Failed to create the invite token!');
|
||||
silentExit(1);
|
||||
}
|
||||
|
||||
|
|
@ -62,7 +64,7 @@ const connect = require('./connect');
|
|||
const appName = process.env.APP_TITLE || 'LibreChat';
|
||||
|
||||
if (!checkEmailConfig()) {
|
||||
console.green('Send this link to the user:', inviteLink);
|
||||
coloredConsole.green(`Send this link to the user: ${inviteLink}`);
|
||||
silentExit(0);
|
||||
}
|
||||
|
||||
|
|
@ -73,17 +75,17 @@ const connect = require('./connect');
|
|||
payload: {
|
||||
appName: appName,
|
||||
inviteLink: inviteLink,
|
||||
year: new Date().getFullYear(),
|
||||
year: String(new Date().getFullYear()),
|
||||
},
|
||||
template: 'inviteUser.handlebars',
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error: ' + error.message);
|
||||
console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
||||
silentExit(1);
|
||||
}
|
||||
|
||||
// Done!
|
||||
console.green('Invitation sent successfully!');
|
||||
coloredConsole.green('Invitation sent successfully!');
|
||||
silentExit(0);
|
||||
})();
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ async function validateDockerRunning() {
|
|||
const imageName = singleCompose ? 'librechat_single' : 'librechat';
|
||||
try {
|
||||
execSync(`${sudo}docker rmi ${imageName}:latest`, { stdio: 'inherit' });
|
||||
} catch (e) {
|
||||
} catch (_error) {
|
||||
console.purple('Failed to remove Docker image librechat:latest. It might not exist.');
|
||||
}
|
||||
console.purple('Removing all unused dangling Docker images...');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue