WIP: app.locals refactoring

WIP: appConfig

fix: update memory configuration retrieval to use getAppConfig based on user role

fix: update comment for AppConfig interface to clarify purpose
This commit is contained in:
Danny Avila 2025-08-05 18:09:25 -04:00
parent 5a14ee9c6a
commit b992fed16c
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956
66 changed files with 706 additions and 366 deletions

View file

@ -6,6 +6,7 @@ const { getOpenAIClient } = require('~/server/controllers/assistants/helpers');
const { updateAction, getActions, deleteAction } = require('~/models/Action');
const { updateAssistantDoc, getAssistant } = require('~/models/Assistant');
const { isActionDomainAllowed } = require('~/server/services/domains');
const { getAppConfig } = require('~/server/services/Config');
const { logger } = require('~/config');
const router = express.Router();
@ -20,6 +21,7 @@ const router = express.Router();
* @returns {Object} 200 - success response - application/json
*/
router.post('/:assistant_id', async (req, res) => {
const appConfig = await getAppConfig({ role: req.user?.role });
try {
const { assistant_id } = req.params;
@ -125,7 +127,7 @@ router.post('/:assistant_id', async (req, res) => {
}
/* Map Azure OpenAI model to the assistant as defined by config */
if (req.app.locals[EModelEndpoint.azureOpenAI]?.assistants) {
if (appConfig[EModelEndpoint.azureOpenAI]?.assistants) {
updatedAssistant = {
...updatedAssistant,
model: req.body.model,

View file

@ -3,6 +3,7 @@ const { isEnabled } = require('@librechat/api');
const { logger } = require('@librechat/data-schemas');
const { CacheKeys, defaultSocialLogins, Constants } = require('librechat-data-provider');
const { getCustomConfig } = require('~/server/services/Config/getCustomConfig');
const { getAppConfig } = require('~/server/services/Config/getAppConfig');
const { getLdapConfig } = require('~/server/services/Config/ldap');
const { getProjectByName } = require('~/models/Project');
const { getMCPManager } = require('~/config');
@ -43,6 +44,8 @@ router.get('/', async function (req, res) {
const ldap = getLdapConfig();
try {
const appConfig = await getAppConfig({ role: req.user?.role });
const isOpenIdEnabled =
!!process.env.OPENID_CLIENT_ID &&
!!process.env.OPENID_CLIENT_SECRET &&
@ -58,7 +61,7 @@ router.get('/', async function (req, res) {
/** @type {TStartupConfig} */
const payload = {
appTitle: process.env.APP_TITLE || 'LibreChat',
socialLogins: req.app.locals.socialLogins ?? defaultSocialLogins,
socialLogins: appConfig.socialLogins ?? defaultSocialLogins,
discordLoginEnabled: !!process.env.DISCORD_CLIENT_ID && !!process.env.DISCORD_CLIENT_SECRET,
facebookLoginEnabled:
!!process.env.FACEBOOK_CLIENT_ID && !!process.env.FACEBOOK_CLIENT_SECRET,
@ -91,10 +94,10 @@ router.get('/', async function (req, res) {
isEnabled(process.env.SHOW_BIRTHDAY_ICON) ||
process.env.SHOW_BIRTHDAY_ICON === '',
helpAndFaqURL: process.env.HELP_AND_FAQ_URL || 'https://librechat.ai',
interface: req.app.locals.interfaceConfig,
turnstile: req.app.locals.turnstileConfig,
modelSpecs: req.app.locals.modelSpecs,
balance: req.app.locals.balance,
interface: appConfig.interfaceConfig,
turnstile: appConfig.turnstileConfig,
modelSpecs: appConfig.modelSpecs,
balance: appConfig.balance,
sharedLinksEnabled,
publicSharedLinksEnabled,
analyticsGtmId: process.env.ANALYTICS_GTM_ID,
@ -128,8 +131,7 @@ router.get('/', async function (req, res) {
}
}
/** @type {TCustomConfig['webSearch']} */
const webSearchConfig = req.app.locals.webSearch;
const webSearchConfig = appConfig.webSearch;
if (
webSearchConfig != null &&
(webSearchConfig.searchProvider ||

View file

@ -2,14 +2,16 @@ const fs = require('fs').promises;
const express = require('express');
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
const { resizeAvatar } = require('~/server/services/Files/images/avatar');
const { filterFile } = require('~/server/services/Files/process');
const { getFileStrategy } = require('~/server/utils/getFileStrategy');
const { filterFile } = require('~/server/services/Files/process');
const { getAppConfig } = require('~/server/services/Config');
const { logger } = require('~/config');
const router = express.Router();
router.post('/', async (req, res) => {
try {
const appConfig = await getAppConfig({ role: req.user?.role });
filterFile({ req, file: req.file, image: true, isAvatar: true });
const userId = req.user.id;
const { manual } = req.body;
@ -19,8 +21,8 @@ router.post('/', async (req, res) => {
throw new Error('User ID is undefined');
}
const fileStrategy = getFileStrategy(req.app.locals, { isAvatar: true });
const desiredFormat = req.app.locals.imageOutputType;
const fileStrategy = getFileStrategy(appConfig, { isAvatar: true });
const desiredFormat = appConfig.imageOutputType;
const resizedBuffer = await resizeAvatar({
userId,
input,
@ -39,7 +41,7 @@ router.post('/', async (req, res) => {
try {
await fs.unlink(req.file.path);
logger.debug('[/files/images/avatar] Temp. image upload file deleted');
} catch (error) {
} catch {
logger.debug('[/files/images/avatar] Temp. image upload file already deleted');
}
}

View file

@ -26,6 +26,7 @@ const { loadAuthValues } = require('~/server/services/Tools/credentials');
const { refreshS3FileUrls } = require('~/server/services/Files/S3/crud');
const { hasAccessToFilesViaAgent } = require('~/server/services/Files');
const { getFiles, batchUpdateFiles } = require('~/models/File');
const { getAppConfig } = require('~/server/services/Config');
const { cleanFileName } = require('~/server/utils/files');
const { getAssistant } = require('~/models/Assistant');
const { getAgent } = require('~/models/Agent');
@ -36,8 +37,9 @@ const router = express.Router();
router.get('/', async (req, res) => {
try {
const appConfig = await getAppConfig({ role: req.user?.role });
const files = await getFiles({ user: req.user.id });
if (req.app.locals.fileStrategy === FileSources.s3) {
if (appConfig.fileStrategy === FileSources.s3) {
try {
const cache = getLogStores(CacheKeys.S3_EXPIRY_INTERVAL);
const alreadyChecked = await cache.get(req.user.id);
@ -114,7 +116,8 @@ router.get('/agent/:agent_id', async (req, res) => {
router.get('/config', async (req, res) => {
try {
res.status(200).json(req.app.locals.fileConfig);
const appConfig = await getAppConfig({ role: req.user?.role });
res.status(200).json(appConfig.fileConfig);
} catch (error) {
logger.error('[/files] Error getting fileConfig', error);
res.status(400).json({ message: 'Error in request', error: error.message });

View file

@ -7,11 +7,13 @@ const {
processImageFile,
processAgentFileUpload,
} = require('~/server/services/Files/process');
const { getAppConfig } = require('~/server/services/Config');
const { logger } = require('~/config');
const router = express.Router();
router.post('/', async (req, res) => {
const appConfig = await getAppConfig({ role: req.user?.role });
const metadata = req.body;
try {
@ -30,7 +32,7 @@ router.post('/', async (req, res) => {
logger.error('[/files/images] Error processing file:', error);
try {
const filepath = path.join(
req.app.locals.paths.imageOutput,
appConfig.paths.imageOutput,
req.user.id,
path.basename(req.file.filename),
);
@ -43,7 +45,7 @@ router.post('/', async (req, res) => {
try {
await fs.unlink(req.file.path);
logger.debug('[/files/images] Temp. image upload file deleted');
} catch (error) {
} catch {
logger.debug('[/files/images] Temp. image upload file already deleted');
}
}

View file

@ -4,11 +4,12 @@ const crypto = require('crypto');
const multer = require('multer');
const { sanitizeFilename } = require('@librechat/api');
const { fileConfig: defaultFileConfig, mergeFileConfig } = require('librechat-data-provider');
const { getCustomConfig } = require('~/server/services/Config');
const { getCustomConfig, getAppConfig } = require('~/server/services/Config');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
const outputPath = path.join(req.app.locals.paths.uploads, 'temp', req.user.id);
destination: async function (req, file, cb) {
const appConfig = await getAppConfig({ role: req.user?.role });
const outputPath = path.join(appConfig.paths.uploads, 'temp', req.user.id);
if (!fs.existsSync(outputPath)) {
fs.mkdirSync(outputPath, { recursive: true });
}

View file

@ -8,6 +8,7 @@ const {
deleteMemory,
setMemory,
} = require('~/models');
const { getAppConfig } = require('~/server/services/Config');
const { requireJwtAuth } = require('~/server/middleware');
const { getRoleByName } = require('~/models/Role');
@ -60,7 +61,8 @@ router.get('/', checkMemoryRead, async (req, res) => {
return sum + (memory.tokenCount || 0);
}, 0);
const memoryConfig = req.app.locals?.memory;
const appConfig = await getAppConfig({ role: req.user?.role });
const memoryConfig = appConfig?.memory;
const tokenLimit = memoryConfig?.tokenLimit;
const charLimit = memoryConfig?.charLimit || 10000;
@ -98,7 +100,8 @@ router.post('/', memoryPayloadLimit, checkMemoryCreate, async (req, res) => {
return res.status(400).json({ error: 'Value is required and must be a non-empty string.' });
}
const memoryConfig = req.app.locals?.memory;
const appConfig = await getAppConfig({ role: req.user?.role });
const memoryConfig = appConfig?.memory;
const charLimit = memoryConfig?.charLimit || 10000;
if (key.length > 1000) {
@ -117,6 +120,9 @@ router.post('/', memoryPayloadLimit, checkMemoryCreate, async (req, res) => {
const tokenCount = Tokenizer.getTokenCount(value, 'o200k_base');
const memories = await getAllUserMemories(req.user.id);
const appConfig = await getAppConfig({ role: req.user?.role });
const memoryConfig = appConfig?.memory;
const tokenLimit = memoryConfig?.tokenLimit;
if (tokenLimit) {
@ -200,8 +206,8 @@ router.patch('/:key', memoryPayloadLimit, checkMemoryUpdate, async (req, res) =>
}
const newKey = bodyKey || urlKey;
const memoryConfig = req.app.locals?.memory;
const appConfig = await getAppConfig({ role: req.user?.role });
const memoryConfig = appConfig?.memory;
const charLimit = memoryConfig?.charLimit || 10000;
if (newKey.length > 1000) {