refactor: decouple caching and DB operations from AppService, make part of consolidated getAppConfig

This commit is contained in:
Danny Avila 2025-08-20 02:03:38 -04:00
parent 28cd234a6c
commit f7ea232760
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956
5 changed files with 58 additions and 33 deletions

View file

@ -24,8 +24,15 @@ const { getConvoTitle, getConvo, saveConvo, deleteConvos } = require('./Conversa
const { getPreset, getPresets, savePreset, deletePresets } = require('./Preset'); const { getPreset, getPresets, savePreset, deletePresets } = require('./Preset');
const { File } = require('~/db/models'); const { File } = require('~/db/models');
const seedDatabase = async () => {
await methods.initializeRoles();
await methods.seedDefaultRoles();
await methods.ensureDefaultCategories();
};
module.exports = { module.exports = {
...methods, ...methods,
seedDatabase,
comparePassword, comparePassword,
findFileById, findFileById,
createFile, createFile,

24
api/models/interface.js Normal file
View file

@ -0,0 +1,24 @@
const { logger } = require('@librechat/data-schemas');
const { updateInterfacePermissions: updateInterfacePerms } = require('@librechat/api');
const { getRoleByName, updateAccessPermissions } = require('./Role');
/**
* Update interface permissions based on app configuration.
* Must be done independently from loading the app config.
* @param {AppConfig} appConfig
*/
async function updateInterfacePermissions(appConfig) {
try {
await updateInterfacePerms({
appConfig,
getRoleByName,
updateAccessPermissions,
});
} catch (error) {
logger.error('Error updating interface permissions:', error);
}
}
module.exports = {
updateInterfacePermissions,
};

View file

@ -14,13 +14,14 @@ const { isEnabled, ErrorController } = require('@librechat/api');
const { connectDb, indexSync } = require('~/db'); const { connectDb, indexSync } = require('~/db');
const validateImageRequest = require('./middleware/validateImageRequest'); const validateImageRequest = require('./middleware/validateImageRequest');
const { jwtLogin, ldapLogin, passportLogin } = require('~/strategies'); const { jwtLogin, ldapLogin, passportLogin } = require('~/strategies');
const { updateInterfacePermissions } = require('~/models/interface');
const { checkMigrations } = require('./services/start/migration'); const { checkMigrations } = require('./services/start/migration');
const initializeMCPs = require('./services/initializeMCPs'); const initializeMCPs = require('./services/initializeMCPs');
const configureSocialLogins = require('./socialLogins'); const configureSocialLogins = require('./socialLogins');
const { getAppConfig } = require('./services/Config'); const { getAppConfig } = require('./services/Config');
const AppService = require('./services/AppService');
const staticCache = require('./utils/staticCache'); const staticCache = require('./utils/staticCache');
const noIndex = require('./middleware/noIndex'); const noIndex = require('./middleware/noIndex');
const { seedDatabase } = require('~/models');
const routes = require('./routes'); const routes = require('./routes');
const { PORT, HOST, ALLOW_SOCIAL_LOGIN, DISABLE_COMPRESSION, TRUST_PROXY } = process.env ?? {}; const { PORT, HOST, ALLOW_SOCIAL_LOGIN, DISABLE_COMPRESSION, TRUST_PROXY } = process.env ?? {};
@ -46,8 +47,10 @@ const startServer = async () => {
app.disable('x-powered-by'); app.disable('x-powered-by');
app.set('trust proxy', trusted_proxy); app.set('trust proxy', trusted_proxy);
await AppService(); await seedDatabase();
const appConfig = await getAppConfig(); const appConfig = await getAppConfig();
await updateInterfacePermissions(appConfig);
const indexPath = path.join(appConfig.paths.dist, 'index.html'); const indexPath = path.join(appConfig.paths.dist, 'index.html');
const indexHTML = fs.readFileSync(indexPath, 'utf8'); const indexHTML = fs.readFileSync(indexPath, 'utf8');

View file

@ -3,6 +3,7 @@ const {
loadMemoryConfig, loadMemoryConfig,
agentsConfigSetup, agentsConfigSetup,
loadWebSearchConfig, loadWebSearchConfig,
loadDefaultInterface,
} = require('@librechat/api'); } = require('@librechat/api');
const { const {
FileSources, FileSources,
@ -16,16 +17,14 @@ const {
checkHealth, checkHealth,
checkConfig, checkConfig,
} = require('./start/checks'); } = require('./start/checks');
const { ensureDefaultCategories, seedDefaultRoles, initializeRoles } = require('~/models');
const { setCachedTools, setAppConfig, loadCustomConfig } = require('./Config');
const { initializeAzureBlobService } = require('./Files/Azure/initialize'); const { initializeAzureBlobService } = require('./Files/Azure/initialize');
const { initializeFirebase } = require('./Files/Firebase/initialize'); const { initializeFirebase } = require('./Files/Firebase/initialize');
const handleRateLimits = require('./Config/handleRateLimits'); const handleRateLimits = require('./Config/handleRateLimits');
const { loadDefaultInterface } = require('./start/interface'); const loadCustomConfig = require('./Config/loadCustomConfig');
const { loadTurnstileConfig } = require('./start/turnstile'); const { loadTurnstileConfig } = require('./start/turnstile');
const { processModelSpecs } = require('./start/modelSpecs'); const { processModelSpecs } = require('./start/modelSpecs');
const { initializeS3 } = require('./Files/S3/initialize'); const { initializeS3 } = require('./Files/S3/initialize');
const { loadAndFormatTools } = require('./ToolService'); const { loadAndFormatTools } = require('./start/tools');
const { loadEndpoints } = require('./start/endpoints'); const { loadEndpoints } = require('./start/endpoints');
const paths = require('~/config/paths'); const paths = require('~/config/paths');
@ -34,9 +33,6 @@ const paths = require('~/config/paths');
* @function AppService * @function AppService
*/ */
const AppService = async () => { const AppService = async () => {
await initializeRoles();
await seedDefaultRoles();
await ensureDefaultCategories();
/** @type {TCustomConfig} */ /** @type {TCustomConfig} */
const config = (await loadCustomConfig()) ?? {}; const config = (await loadCustomConfig()) ?? {};
const configDefaults = getConfigDefaults(); const configDefaults = getConfigDefaults();
@ -73,17 +69,11 @@ const AppService = async () => {
adminFilter: filteredTools, adminFilter: filteredTools,
adminIncluded: includedTools, adminIncluded: includedTools,
directory: paths.structuredTools, directory: paths.structuredTools,
imageOutputType,
fileStrategy,
}); });
await setCachedTools(availableTools, { isGlobal: true });
// Store MCP config for later initialization
const mcpConfig = config.mcpServers || null; const mcpConfig = config.mcpServers || null;
const registration = config.registration ?? configDefaults.registration; const registration = config.registration ?? configDefaults.registration;
const interfaceConfig = await loadDefaultInterface(config, configDefaults); const interfaceConfig = await loadDefaultInterface({ config, configDefaults });
const turnstileConfig = loadTurnstileConfig(config, configDefaults); const turnstileConfig = loadTurnstileConfig(config, configDefaults);
const speech = config.speech; const speech = config.speech;
@ -100,6 +90,7 @@ const AppService = async () => {
registration, registration,
filteredTools, filteredTools,
includedTools, includedTools,
availableTools,
imageOutputType, imageOutputType,
interfaceConfig, interfaceConfig,
turnstileConfig, turnstileConfig,
@ -115,8 +106,7 @@ const AppService = async () => {
[EModelEndpoint.agents]: agentsDefaults, [EModelEndpoint.agents]: agentsDefaults,
}, },
}; };
await setAppConfig(appConfig); return appConfig;
return;
} }
checkConfig(config); checkConfig(config);
@ -131,7 +121,7 @@ const AppService = async () => {
endpoints: loadedEndpoints, endpoints: loadedEndpoints,
}; };
await setAppConfig(appConfig); return appConfig;
}; };
module.exports = AppService; module.exports = AppService;

View file

@ -1,5 +1,7 @@
const { logger } = require('@librechat/data-schemas'); const { logger } = require('@librechat/data-schemas');
const { CacheKeys } = require('librechat-data-provider'); const { CacheKeys } = require('librechat-data-provider');
const AppService = require('~/server/services/AppService');
const { setCachedTools } = require('./getCachedTools');
const getLogStores = require('~/cache/getLogStores'); const getLogStores = require('~/cache/getLogStores');
/** /**
@ -22,9 +24,20 @@ async function getAppConfig(options = {}) {
} }
} }
const baseConfig = await cache.get(CacheKeys.APP_CONFIG); let baseConfig = await cache.get(CacheKeys.APP_CONFIG);
if (!baseConfig) { if (!baseConfig) {
throw new Error('App configuration not initialized. Please ensure AppService has been called.'); logger.info('[getAppConfig] App configuration not initialized. Initializing AppService...');
baseConfig = await AppService();
if (!baseConfig) {
throw new Error('Failed to initialize app configuration through AppService.');
}
if (baseConfig.availableTools) {
await setCachedTools(baseConfig.availableTools, { isGlobal: true });
}
await cache.set(CacheKeys.APP_CONFIG, baseConfig);
} }
// For now, return the base config // For now, return the base config
@ -49,19 +62,7 @@ async function clearAppConfigCache() {
return await cache.delete(cacheKey); return await cache.delete(cacheKey);
} }
/**
* Initialize the app configuration during startup
* @param {AppConfig} config - The initial configuration to store
* @returns {Promise<void>}
*/
async function setAppConfig(config) {
const cache = getLogStores(CacheKeys.CONFIG_STORE);
await cache.set(CacheKeys.APP_CONFIG, config);
logger.debug('[getAppConfig] App configuration initialized');
}
module.exports = { module.exports = {
getAppConfig, getAppConfig,
setAppConfig,
clearAppConfigCache, clearAppConfigCache,
}; };