diff --git a/api/src/controllers/admin.controller.ts b/api/src/controllers/admin.controller.ts index de71f55..916024f 100644 --- a/api/src/controllers/admin.controller.ts +++ b/api/src/controllers/admin.controller.ts @@ -1,7 +1,9 @@ import type { Response } from 'express'; import { createRequire } from 'node:module'; +import fs from 'node:fs'; import path from 'node:path'; import process from 'node:process'; +import { fileURLToPath } from 'node:url'; import { z } from 'zod'; import { AppDataSource } from '../config/data-source.js'; import { env } from '../config/env.js'; @@ -37,10 +39,50 @@ const userUpdateSchema = z.object({ defaultCurrency: z.string().min(3).max(8).optional() }); +type PackageJson = { version?: string }; + const require = createRequire(import.meta.url); -const rootPackage = require(path.resolve(process.cwd(), '..', 'package.json')) as { version?: string }; -const apiPackage = require(path.resolve(process.cwd(), 'package.json')) as { version?: string }; -const webPackage = require(path.resolve(process.cwd(), '..', 'web', 'package.json')) as { version?: string }; +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const readPackageJsonSafe = (filePath: string | null): PackageJson | null => { + if (!filePath || !fs.existsSync(filePath)) { + return null; + } + + try { + return JSON.parse(fs.readFileSync(filePath, 'utf8')) as PackageJson; + } catch { + return null; + } +}; + +const findNearestPackageJson = (startDir: string): string | null => { + let currentDir = path.resolve(startDir); + + while (true) { + const candidate = path.join(currentDir, 'package.json'); + if (fs.existsSync(candidate)) { + return candidate; + } + + const parentDir = path.dirname(currentDir); + if (parentDir === currentDir) { + return null; + } + + currentDir = parentDir; + } +}; + +const apiPackagePath = findNearestPackageJson(__dirname); +const apiPackage = readPackageJsonSafe(apiPackagePath); +const apiRootDir = apiPackagePath ? path.dirname(apiPackagePath) : null; +const projectRootPackagePath = apiRootDir ? findNearestPackageJson(path.dirname(apiRootDir)) : null; +const rootPackage = readPackageJsonSafe(projectRootPackagePath); +const webPackage = readPackageJsonSafe( + projectRootPackagePath ? path.join(path.dirname(projectRootPackagePath), 'web', 'package.json') : null +); const settingsRepo = () => AppDataSource.getRepository(AppSetting); const userRepo = () => AppDataSource.getRepository(User); @@ -179,9 +221,9 @@ export const getSystemInfo = async (_req: AuthenticatedRequest, res: Response) = return res.json({ item: { appName: settings?.appName ?? 'Expense Control', - suiteVersion: rootPackage.version ?? '0.0.0', - apiVersion: apiPackage.version ?? '0.0.0', - webVersion: webPackage.version ?? '0.0.0', + suiteVersion: rootPackage?.version ?? apiPackage?.version ?? '0.0.0', + apiVersion: apiPackage?.version ?? '0.0.0', + webVersion: webPackage?.version ?? '0.0.0', nodeVersion: process.version, environment: process.env.NODE_ENV ?? 'development', database: env.DB_TYPE,