From 9105507722f7029fd217a1ceb97c7b45572ea800 Mon Sep 17 00:00:00 2001 From: samanhappy Date: Sun, 26 Oct 2025 19:27:30 +0800 Subject: [PATCH] Refactor: Clean up code formatting and improve readability across multiple files (#387) --- src/config/index.ts | 126 ++++++++++----------- src/controllers/authController.ts | 5 +- src/controllers/oauthCallbackController.ts | 28 +++-- src/controllers/serverController.ts | 2 +- src/server.ts | 2 +- src/services/mcpOAuthProvider.ts | 11 +- src/services/mcpService.ts | 4 +- src/utils/path.ts | 38 ++++--- src/utils/version.ts | 4 +- 9 files changed, 111 insertions(+), 109 deletions(-) diff --git a/src/config/index.ts b/src/config/index.ts index 31b22bd..09c6beb 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -1,12 +1,12 @@ -import dotenv from 'dotenv' -import fs from 'fs' -import { McpSettings, IUser } from '../types/index.js' -import { getConfigFilePath } from '../utils/path.js' -import { getPackageVersion } from '../utils/version.js' -import { getDataService } from '../services/services.js' -import { DataService } from '../services/dataService.js' +import dotenv from 'dotenv'; +import fs from 'fs'; +import { McpSettings, IUser } from '../types/index.js'; +import { getConfigFilePath } from '../utils/path.js'; +import { getPackageVersion } from '../utils/version.js'; +import { getDataService } from '../services/services.js'; +import { DataService } from '../services/dataService.js'; -dotenv.config() +dotenv.config(); const defaultConfig = { port: process.env.PORT || 3000, @@ -15,74 +15,74 @@ const defaultConfig = { readonly: 'true' === process.env.READONLY || false, mcpHubName: 'mcphub', mcpHubVersion: getPackageVersion(), -} +}; -const dataService: DataService = getDataService() +const dataService: DataService = getDataService(); // Settings cache -let settingsCache: McpSettings | null = null +let settingsCache: McpSettings | null = null; export const getSettingsPath = (): string => { - return getConfigFilePath('mcp_settings.json', 'Settings') -} + return getConfigFilePath('mcp_settings.json', 'Settings'); +}; export const loadOriginalSettings = (): McpSettings => { // If cache exists, return cached data directly if (settingsCache) { - return settingsCache + return settingsCache; } - const settingsPath = getSettingsPath() + const settingsPath = getSettingsPath(); // check if file exists if (!fs.existsSync(settingsPath)) { - console.warn(`Settings file not found at ${settingsPath}, using default settings.`) - const defaultSettings = { mcpServers: {}, users: [] } + console.warn(`Settings file not found at ${settingsPath}, using default settings.`); + const defaultSettings = { mcpServers: {}, users: [] }; // Cache default settings - settingsCache = defaultSettings - return defaultSettings + settingsCache = defaultSettings; + return defaultSettings; } try { // Read and parse settings file - const settingsData = fs.readFileSync(settingsPath, 'utf8') - const settings = JSON.parse(settingsData) + const settingsData = fs.readFileSync(settingsPath, 'utf8'); + const settings = JSON.parse(settingsData); // Update cache - settingsCache = settings + settingsCache = settings; - console.log(`Loaded settings from ${settingsPath}`) - return settings + console.log(`Loaded settings from ${settingsPath}`); + return settings; } catch (error) { - throw new Error(`Failed to load settings from ${settingsPath}: ${error}`) + throw new Error(`Failed to load settings from ${settingsPath}: ${error}`); } -} +}; export const loadSettings = (user?: IUser): McpSettings => { - return dataService.filterSettings!(loadOriginalSettings(), user) -} + return dataService.filterSettings!(loadOriginalSettings(), user); +}; export const saveSettings = (settings: McpSettings, user?: IUser): boolean => { - const settingsPath = getSettingsPath() + const settingsPath = getSettingsPath(); try { - const mergedSettings = dataService.mergeSettings!(loadOriginalSettings(), settings, user) - fs.writeFileSync(settingsPath, JSON.stringify(mergedSettings, null, 2), 'utf8') + const mergedSettings = dataService.mergeSettings!(loadOriginalSettings(), settings, user); + fs.writeFileSync(settingsPath, JSON.stringify(mergedSettings, null, 2), 'utf8'); // Update cache after successful save - settingsCache = mergedSettings + settingsCache = mergedSettings; - return true + return true; } catch (error) { - console.error(`Failed to save settings to ${settingsPath}:`, error) - return false + console.error(`Failed to save settings to ${settingsPath}:`, error); + return false; } -} +}; /** * Clear settings cache, force next loadSettings call to re-read from file */ export const clearSettingsCache = (): void => { - settingsCache = null -} + settingsCache = null; +}; /** * Get current cache status (for debugging) @@ -90,71 +90,71 @@ export const clearSettingsCache = (): void => { export const getSettingsCacheInfo = (): { hasCache: boolean } => { return { hasCache: settingsCache !== null, - } -} + }; +}; -export function replaceEnvVars(input: Record): Record -export function replaceEnvVars(input: string[] | undefined): string[] -export function replaceEnvVars(input: string): string +export function replaceEnvVars(input: Record): Record; +export function replaceEnvVars(input: string[] | undefined): string[]; +export function replaceEnvVars(input: string): string; export function replaceEnvVars( input: Record | string[] | string | undefined, ): Record | string[] | string { // Handle object input - recursively expand all nested values if (input && typeof input === 'object' && !Array.isArray(input)) { - const res: Record = {} + const res: Record = {}; for (const [key, value] of Object.entries(input)) { if (typeof value === 'string') { - res[key] = expandEnvVars(value) + res[key] = expandEnvVars(value); } else if (typeof value === 'object' && value !== null) { // Recursively handle nested objects and arrays - res[key] = replaceEnvVars(value as any) + res[key] = replaceEnvVars(value as any); } else { // Preserve non-string, non-object values (numbers, booleans, etc.) - res[key] = value + res[key] = value; } } - return res + return res; } // Handle array input - recursively expand all elements if (Array.isArray(input)) { return input.map((item) => { if (typeof item === 'string') { - return expandEnvVars(item) + return expandEnvVars(item); } else if (typeof item === 'object' && item !== null) { - return replaceEnvVars(item as any) + return replaceEnvVars(item as any); } - return item - }) + return item; + }); } // Handle string input if (typeof input === 'string') { - return expandEnvVars(input) + return expandEnvVars(input); } // Handle undefined/null array input if (input === undefined || input === null) { - return [] + return []; } - return input + return input; } export const expandEnvVars = (value: string): string => { if (typeof value !== 'string') { - return String(value) + return String(value); } // Replace ${VAR} format - let result = value.replace(/\$\{([^}]+)\}/g, (_, key) => process.env[key] || '') + let result = value.replace(/\$\{([^}]+)\}/g, (_, key) => process.env[key] || ''); // Also replace $VAR format (common on Unix-like systems) - result = result.replace(/\$([A-Z_][A-Z0-9_]*)/g, (_, key) => process.env[key] || '') - return result -} + result = result.replace(/\$([A-Z_][A-Z0-9_]*)/g, (_, key) => process.env[key] || ''); + return result; +}; -export default defaultConfig +export default defaultConfig; export function getNameSeparator(): string { - const settings = loadSettings() - return settings.systemConfig?.nameSeparator || '-' + const settings = loadSettings(); + return settings.systemConfig?.nameSeparator || '-'; } diff --git a/src/controllers/authController.ts b/src/controllers/authController.ts index 01c0cd1..4c080c6 100644 --- a/src/controllers/authController.ts +++ b/src/controllers/authController.ts @@ -69,10 +69,7 @@ export const login = async (req: Request, res: Response): Promise => { // Check if user is admin with default password const version = getPackageVersion(); const isUsingDefaultPassword = - user.username === 'admin' && - user.isAdmin && - isDefaultPassword(password) && - version !== 'dev'; + user.username === 'admin' && user.isAdmin && isDefaultPassword(password) && version !== 'dev'; jwt.sign(payload, JWT_SECRET, { expiresIn: TOKEN_EXPIRY }, (err, token) => { if (err) throw err; diff --git a/src/controllers/oauthCallbackController.ts b/src/controllers/oauthCallbackController.ts index 99d4df4..a30f27a 100644 --- a/src/controllers/oauthCallbackController.ts +++ b/src/controllers/oauthCallbackController.ts @@ -126,21 +126,19 @@ export const handleOAuthCallback = async (req: Request, res: Response) => { // Check for authorization errors if (error) { console.error(`OAuth authorization failed: ${error} - ${error_description || ''}`); - return res - .status(400) - .send( - generateHtmlResponse('error', t('oauthCallback.authorizationFailed'), '', [ - { label: t('oauthCallback.authorizationFailedError'), value: String(error) }, - ...(error_description - ? [ - { - label: t('oauthCallback.authorizationFailedDetails'), - value: String(error_description), - }, - ] - : []), - ]), - ); + return res.status(400).send( + generateHtmlResponse('error', t('oauthCallback.authorizationFailed'), '', [ + { label: t('oauthCallback.authorizationFailedError'), value: String(error) }, + ...(error_description + ? [ + { + label: t('oauthCallback.authorizationFailedDetails'), + value: String(error_description), + }, + ] + : []), + ]), + ); } // Validate required parameters diff --git a/src/controllers/serverController.ts b/src/controllers/serverController.ts index dfee247..e6ca1b0 100644 --- a/src/controllers/serverController.ts +++ b/src/controllers/serverController.ts @@ -529,7 +529,7 @@ export const updateSystemConfig = (req: Request, res: Response): void => { typeof mcpRouter.referer !== 'string' && typeof mcpRouter.title !== 'string' && typeof mcpRouter.baseUrl !== 'string')) && - (typeof nameSeparator !== 'string') + typeof nameSeparator !== 'string' ) { res.status(400).json({ success: false, diff --git a/src/server.ts b/src/server.ts index 2657316..6ef654e 100644 --- a/src/server.ts +++ b/src/server.ts @@ -28,7 +28,7 @@ function getCurrentFileDir(): string { if (process.env.NODE_ENV === 'test' || process.env.JEST_WORKER_ID !== undefined) { return process.cwd(); } - + try { return getCurrentModuleDir(); } catch { diff --git a/src/services/mcpOAuthProvider.ts b/src/services/mcpOAuthProvider.ts index 37df819..1739afd 100644 --- a/src/services/mcpOAuthProvider.ts +++ b/src/services/mcpOAuthProvider.ts @@ -333,7 +333,7 @@ export class MCPHubOAuthProvider implements OAuthClientProvider { const updatedConfig = await persistTokens(this.serverName, { accessToken: tokens.access_token, - refreshToken: refreshTokenProvided ? tokens.refresh_token ?? null : undefined, + refreshToken: refreshTokenProvided ? (tokens.refresh_token ?? null) : undefined, clearPendingAuthorization: hadPending, }); @@ -421,7 +421,9 @@ export class MCPHubOAuthProvider implements OAuthClientProvider { async saveCodeVerifier(verifier: string): Promise { this._codeVerifier = verifier; try { - const updatedConfig = await updatePendingAuthorization(this.serverName, { codeVerifier: verifier }); + const updatedConfig = await updatePendingAuthorization(this.serverName, { + codeVerifier: verifier, + }); if (updatedConfig) { this.serverConfig = updatedConfig; } @@ -490,7 +492,10 @@ export class MCPHubOAuthProvider implements OAuthClientProvider { if (scope === 'client' || scope === 'all') { const supportsDynamicClient = currentConfig.oauth.dynamicRegistration?.enabled === true; - if (supportsDynamicClient && (currentConfig.oauth.clientId || currentConfig.oauth.clientSecret)) { + if ( + supportsDynamicClient && + (currentConfig.oauth.clientId || currentConfig.oauth.clientSecret) + ) { removeRegisteredClient(this.serverName); const updated = await clearOAuthData(this.serverName, 'client'); assignUpdatedConfig(updated); diff --git a/src/services/mcpService.ts b/src/services/mcpService.ts index 2651dbe..3510a60 100644 --- a/src/services/mcpService.ts +++ b/src/services/mcpService.ts @@ -380,10 +380,10 @@ export const initializeClientsFromSettings = async ( try { for (const conf of allServers) { const { name } = conf; - + // Expand environment variables in all configuration values const expandedConf = replaceEnvVars(conf as any) as ServerConfigWithName; - + // Skip disabled servers if (expandedConf.enabled === false) { console.log(`Skipping disabled server: ${name}`); diff --git a/src/utils/path.ts b/src/utils/path.ts index e6a670a..10ed7db 100644 --- a/src/utils/path.ts +++ b/src/utils/path.ts @@ -18,18 +18,18 @@ function initializePackageRoot(): void { if (process.env.NODE_ENV === 'test' || process.env.JEST_WORKER_ID !== undefined) { return; } - + try { // Try to get the current module's directory const currentModuleDir = getCurrentModuleDir(); - + // This file is in src/utils/path.ts (or dist/utils/path.js when compiled) // So package.json should be 2 levels up const possibleRoots = [ path.resolve(currentModuleDir, '..', '..'), // dist -> package root path.resolve(currentModuleDir, '..'), // dist/utils -> dist -> package root ]; - + for (const root of possibleRoots) { const packageJsonPath = path.join(root, 'package.json'); if (fs.existsSync(packageJsonPath)) { @@ -66,10 +66,10 @@ export const findPackageRoot = (startPath?: string): string | null => { } const debug = process.env.DEBUG === 'true'; - + // Possible locations for package.json relative to the search path const possibleRoots: string[] = []; - + if (startPath) { // When start path is provided (from fileURLToPath(import.meta.url)) possibleRoots.push( @@ -78,25 +78,30 @@ export const findPackageRoot = (startPath?: string): string | null => { // When in dist/ (compiled code) - go up 1 level path.resolve(startPath, '..'), // Direct parent directories - path.resolve(startPath) + path.resolve(startPath), ); } - + // Try to use require.resolve to find the module location (works in CommonJS and ESM with createRequire) try { // In ESM, we can use import.meta.resolve, but it's async in some versions // So we'll try to find the module by checking the node_modules structure - + // Check if this file is in a node_modules installation const currentFile = new Error().stack?.split('\n')[2]?.match(/\((.+?):\d+:\d+\)$/)?.[1]; if (currentFile) { const nodeModulesIndex = currentFile.indexOf('node_modules'); if (nodeModulesIndex !== -1) { // Extract the package path from node_modules - const afterNodeModules = currentFile.substring(nodeModulesIndex + 'node_modules'.length + 1); + const afterNodeModules = currentFile.substring( + nodeModulesIndex + 'node_modules'.length + 1, + ); const packageNameEnd = afterNodeModules.indexOf(path.sep); if (packageNameEnd !== -1) { - const packagePath = currentFile.substring(0, nodeModulesIndex + 'node_modules'.length + 1 + packageNameEnd); + const packagePath = currentFile.substring( + 0, + nodeModulesIndex + 'node_modules'.length + 1 + packageNameEnd, + ); possibleRoots.push(packagePath); } } @@ -108,18 +113,15 @@ export const findPackageRoot = (startPath?: string): string | null => { // Check module.filename location (works in Node.js when available) if (typeof __filename !== 'undefined') { const moduleDir = path.dirname(__filename); - possibleRoots.push( - path.resolve(moduleDir, '..', '..'), - path.resolve(moduleDir, '..') - ); + possibleRoots.push(path.resolve(moduleDir, '..', '..'), path.resolve(moduleDir, '..')); } - + // Check common installation locations possibleRoots.push( // Current working directory (for development/tests) process.cwd(), // Parent of cwd - path.resolve(process.cwd(), '..') + path.resolve(process.cwd(), '..'), ); if (debug) { @@ -157,12 +159,12 @@ export const findPackageRoot = (startPath?: string): string | null => { if (debug) { console.warn('DEBUG: Could not find package root directory'); } - + // Cache null result as well to avoid repeated searches if (!startPath) { cachedPackageRoot = null; } - + return null; }; diff --git a/src/utils/version.ts b/src/utils/version.ts index 19a2fc8..e8358c7 100644 --- a/src/utils/version.ts +++ b/src/utils/version.ts @@ -11,13 +11,13 @@ export const getPackageVersion = (searchPath?: string): string => { try { // Use provided path or fallback to current working directory const startPath = searchPath || process.cwd(); - + const packageRoot = findPackageRoot(startPath); if (!packageRoot) { console.warn('Could not find package root, using default version'); return 'dev'; } - + const packageJsonPath = path.join(packageRoot, 'package.json'); const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8'); const packageJson = JSON.parse(packageJsonContent);