const fs = require("fs"); const path = require("path"); const root = path.resolve(__dirname, ".."); function fail(message, error) { console.error(`[verify] ${message}`); if (error) { console.error(`[verify] ${error instanceof Error ? error.message : String(error)}`); } if (process.platform === "win32") { console.error("[verify] Retry with windows\\install.bat."); console.error("[verify] Native fallback: run C:\\Program Files\\nodejs\\install_tools.bat as Administrator."); } process.exit(1); } function warn(message) { console.warn(`[verify] WARNING: ${message}`); } function compareVersions(left, right) { const leftParts = String(left || "").split(".").map((part) => Number(part) || 0); const rightParts = String(right || "").split(".").map((part) => Number(part) || 0); const length = Math.max(leftParts.length, rightParts.length); for (let index = 0; index < length; index += 1) { const difference = (leftParts[index] || 0) - (rightParts[index] || 0); if (difference !== 0) return difference; } return 0; } try { require("express"); } catch (error) { fail("Express could not be loaded.", error); } try { const Database = require("better-sqlite3"); const db = new Database(":memory:"); const row = db.prepare("SELECT 1 AS ok").get(); db.close(); if (row?.ok !== 1) { fail("SQLite verification query returned an unexpected result."); } } catch (error) { fail("better-sqlite3 could not be loaded or initialized.", error); } for (const directory of ["data", "logs"]) { fs.mkdirSync(path.join(root, directory), { recursive: true }); } if (process.platform === "win32") { const ammcDir = path.join(root, "AMMC", "windows64"); const requiredFiles = ["ammc-amb.exe", "ammc.dll", "MyLapsSDK.dll"]; const missingFiles = requiredFiles.filter((file) => !fs.existsSync(path.join(ammcDir, file))); if (missingFiles.length > 0) { fail(`Bundled AMMC runtime is incomplete: ${missingFiles.join(", ")}`); } console.log(`[verify] AMMC Windows runtime: ${ammcDir}`); } function verifyUnixAmmcExecutables(directory, executableNames, runtimeLabel) { const missingFiles = []; const nonExecutableFiles = []; for (const executableName of executableNames) { const executablePath = path.join(directory, executableName); if (!fs.existsSync(executablePath)) { missingFiles.push(executableName); continue; } try { fs.accessSync(executablePath, fs.constants.X_OK); } catch { nonExecutableFiles.push(executableName); } } if (missingFiles.length > 0) { warn(`Bundled ${runtimeLabel} tools are missing: ${missingFiles.join(", ")}`); } if (nonExecutableFiles.length > 0) { warn(`Bundled ${runtimeLabel} tools are not executable: ${nonExecutableFiles.join(", ")}. Run: chmod +x ${path.relative(root, directory)}/ammc-*`); } return missingFiles.length === 0 && nonExecutableFiles.length === 0; } if (process.platform === "linux" && process.arch === "x64") { const ammcDir = path.join(root, "AMMC", "linux_x86-64"); const executableNames = ["ammc-amb", "ammc-prochip", "ammc-sim", "ammc-vostok", "ammc-x2"]; const requiredGlibc = "2.39"; const runtimeReady = verifyUnixAmmcExecutables(ammcDir, executableNames, "Linux AMMC"); const glibcVersion = process.report?.getReport?.().header?.glibcVersionRuntime || ""; if (!glibcVersion) { warn(`Could not detect the host GLIBC version. The bundled Linux AMMC tools require GLIBC ${requiredGlibc} or newer.`); } else if (compareVersions(glibcVersion, requiredGlibc) < 0) { warn(`Host GLIBC ${glibcVersion} is too old for the bundled Linux AMMC tools (requires >= ${requiredGlibc}). RC RaceCore can still run, but use a compatible AMMC build or a newer Linux distribution. Do not replace the system GLIBC manually.`); } else if (runtimeReady) { console.log(`[verify] AMMC Linux runtime: ${ammcDir} (all tools executable; GLIBC ${glibcVersion}, requires >= ${requiredGlibc})`); } } if (process.platform === "darwin" && process.arch === "arm64") { const ammcDir = path.join(root, "AMMC", "apple_m"); const executableNames = ["ammc-amb", "ammc-prochip", "ammc-sim", "ammc-vostok"]; if (verifyUnixAmmcExecutables(ammcDir, executableNames, "Apple Silicon AMMC")) { console.log(`[verify] AMMC Apple Silicon runtime: ${ammcDir} (all tools executable)`); } } console.log(`[verify] Express and SQLite: OK (${process.platform}/${process.arch}, Node ${process.version})`); console.log(`[verify] Installation is ready. Start with: ${process.platform === "win32" ? "npm.cmd start" : "npm start"}`);