diff --git a/src/app/api/settings/require-login/route.ts b/src/app/api/settings/require-login/route.ts index 547ac96859..6b33fadb21 100644 --- a/src/app/api/settings/require-login/route.ts +++ b/src/app/api/settings/require-login/route.ts @@ -4,17 +4,25 @@ import bcrypt from "bcryptjs"; import { updateRequireLoginSchema } from "@/shared/validation/schemas"; import { isValidationFailure, validateBody } from "@/shared/validation/helpers"; +// Node.js compatibility check — better-sqlite3 requires Node <24 +function getNodeCompatibility() { + const nodeVersion = process.version; + const major = parseInt(nodeVersion.replace("v", "").split(".")[0], 10); + return { nodeVersion, nodeCompatible: major >= 18 && major < 24 }; +} + export async function GET() { + const nodeInfo = getNodeCompatibility(); try { const settings = await getSettings(); const requireLogin = settings.requireLogin !== false; const hasPassword = !!settings.password || !!process.env.INITIAL_PASSWORD; const setupComplete = !!settings.setupComplete; - return NextResponse.json({ requireLogin, hasPassword, setupComplete }); + return NextResponse.json({ requireLogin, hasPassword, setupComplete, ...nodeInfo }); } catch (error) { console.error("[API] Error fetching require-login settings:", error); return NextResponse.json( - { requireLogin: true, hasPassword: true, setupComplete: true }, + { requireLogin: true, hasPassword: true, setupComplete: true, ...nodeInfo }, { status: 200 } ); } diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index e17e0c53b3..edd0f8228a 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -14,6 +14,8 @@ export default function LoginPage() { const [hasPassword, setHasPassword] = useState(null); const [setupComplete, setSetupComplete] = useState(null); const [mounted, setMounted] = useState(false); + const [nodeVersion, setNodeVersion] = useState(null); + const [nodeCompatible, setNodeCompatible] = useState(true); const router = useRouter(); useEffect(() => { @@ -31,6 +33,8 @@ export default function LoginPage() { if (res.ok) { const data = await res.json(); + if (data.nodeVersion) setNodeVersion(data.nodeVersion); + if (data.nodeCompatible === false) setNodeCompatible(false); if (data.requireLogin === false) { router.push("/dashboard"); router.refresh(); @@ -83,9 +87,39 @@ export default function LoginPage() { } }; + const nodeWarningBanner = !nodeCompatible && nodeVersion ? ( +
+ {t("nodeIncompatibleDesc", { version: nodeVersion })} +
+nvm install 22 && nvm use 22
+ + info + {t("nodeIncompatibleHint")} +
+