LibreChat / config /upgrade.js
AchyuthGamer's picture
Upload 683 files
9705b6c
raw
history blame contribute delete
No virus
5.49 kB
/**
* Upgrade script
*/
const dotenv = require('dotenv');
const fs = require('fs');
const { exit } = require('process');
// Suppress default warnings
const originalConsoleWarn = console.warn;
console.warn = () => {};
const loader = require('./loader');
console.warn = originalConsoleWarn;
// Old Paths
const apiEnvPath = loader.resolve('api/.env');
const clientEnvPath = loader.resolve('client/.env');
// Load into env
dotenv.config({
path: loader.resolve(apiEnvPath),
});
dotenv.config({
path: loader.resolve(clientEnvPath),
});
// JS was doing spooky actions at a distance, lets prevent that
const initEnv = JSON.parse(JSON.stringify(process.env));
// New Paths
const rootEnvPath = loader.resolve('.env');
const devEnvPath = loader.resolve('.env.development');
const prodEnvPath = loader.resolve('.env.production');
if (fs.existsSync(rootEnvPath)) {
console.error('Root env file already exists! Aborting');
exit(1);
}
// Validate old configs
if (!fs.existsSync(apiEnvPath)) {
console.error('Api env doesn\'t exit! Did you mean to run install?');
exit(1);
}
if (!fs.existsSync(clientEnvPath)) {
console.error('Client env doesn\'t exit! But api/.env does. Manual upgrade required');
exit(1);
}
/**
* Refactor the ENV if it has a prod_/dev_ version
*
* @param {*} varDev
* @param {*} varProd
* @param {*} varName
*/
function refactorPairedEnvVar(varDev, varProd, varName) {
// Lets validate if either of these are undefined, if so lets use the non-undefined one
if (initEnv[varDev] === undefined && initEnv[varProd] === undefined) {
console.error(`Both ${varDev} and ${varProd} are undefined! Manual intervention required!`);
} else if (initEnv[varDev] === undefined) {
fs.appendFileSync(rootEnvPath, `\n${varName}=${initEnv[varProd]}`);
} else if (initEnv[varProd] === undefined) {
fs.appendFileSync(rootEnvPath, `\n${varName}=${initEnv[varDev]}`);
} else if (initEnv[varDev] === initEnv[varProd]) {
fs.appendFileSync(rootEnvPath, `\n${varName}=${initEnv[varDev]}`);
} else {
fs.appendFileSync(rootEnvPath, `${varName}=${initEnv[varProd]}\n`);
fs.appendFileSync(devEnvPath, `${varName}=${initEnv[varDev]}\n`);
}
}
/**
* Upgrade the env files!
* 1. /api/.env will merge into /.env
* 2. /client/.env will merge into /.env
* 3. Any prod_/dev_ keys will be split up into .env.development / .env.production files (if they are different)
*/
if (fs.existsSync(apiEnvPath)) {
fs.copyFileSync(apiEnvPath, rootEnvPath);
fs.copyFileSync(apiEnvPath, rootEnvPath + '.api.bak');
fs.unlinkSync(apiEnvPath);
}
// Clean up Domain variables
fs.appendFileSync(
rootEnvPath,
'\n\n##########################\n# Domain Variables:\n# Note: DOMAIN_ vars are passed to vite\n##########################\n',
);
refactorPairedEnvVar('CLIENT_URL_DEV', 'CLIENT_URL_PROD', 'DOMAIN_CLIENT');
refactorPairedEnvVar('SERVER_URL_DEV', 'SERVER_URL_PROD', 'DOMAIN_SERVER');
// Remove the old vars
const removeEnvs = {
NODE_ENV: 'remove',
OPENAI_KEY: 'remove',
CLIENT_URL_DEV: 'remove',
CLIENT_URL_PROD: 'remove',
SERVER_URL_DEV: 'remove',
SERVER_URL_PROD: 'remove',
JWT_SECRET_DEV: 'remove', // Lets regen
JWT_SECRET_PROD: 'remove', // Lets regen
VITE_APP_TITLE: 'remove',
// Comments to remove:
'#JWT:': 'remove',
'# Add a secure secret for production if deploying to live domain.': 'remove',
'# Site URLs:': 'remove',
'# Don\'t forget to set Node env to development in the Server configuration section above':
'remove',
'# if you want to run in dev mode': 'remove',
'# Change these values to domain if deploying:': 'remove',
'# Set Node env to development if running in dev mode.': 'remove',
};
loader.writeEnvFile(rootEnvPath, removeEnvs);
/**
* Lets make things more secure!
* 1. Add CREDS_KEY
* 2. Add CREDS_IV
* 3. Add JWT_SECRET
*/
fs.appendFileSync(
rootEnvPath,
'\n\n##########################\n# Secure Keys:\n##########################\n',
);
loader.addSecureEnvVar(rootEnvPath, 'CREDS_KEY', 32);
loader.addSecureEnvVar(rootEnvPath, 'CREDS_IV', 16);
loader.addSecureEnvVar(rootEnvPath, 'JWT_SECRET', 32);
// Lets update the openai key name, not the best spot in the env file but who cares ¯\_(ツ)_/¯
loader.writeEnvFile(rootEnvPath, { OPENAI_API_KEY: initEnv['OPENAI_KEY'] });
// TODO: we need to copy over the value of: APP_TITLE
fs.appendFileSync(
rootEnvPath,
'\n\n##########################\n# Frontend Vite Variables:\n##########################\n',
);
const frontend = {
APP_TITLE: initEnv['VITE_APP_TITLE'] || '"LibreChat"',
ALLOW_REGISTRATION: 'true',
};
loader.writeEnvFile(rootEnvPath, frontend);
// Ensure .env.development and .env.production files end with a newline
if (fs.existsSync(devEnvPath)) {
fs.appendFileSync(devEnvPath, '\n');
}
if (fs.existsSync(prodEnvPath)) {
fs.appendFileSync(prodEnvPath, '\n');
}
// Remove client file
fs.copyFileSync(clientEnvPath, rootEnvPath + '.client.bak');
fs.unlinkSync(clientEnvPath);
console.log('###############################################');
console.log('Upgrade completed! Please review the new .env file and make any changes as needed.');
console.log('###############################################');
// if the .env.development file exists, lets tell the user
if (fs.existsSync(devEnvPath)) {
console.log(
'NOTE: A .env.development file was created. This will take precedence over the .env file when running in dev mode.',
);
console.log('###############################################');
}