From 25c81966418dfb2a784da5b41962697253a45fcd Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Mon, 17 Jul 2023 13:17:00 +0800
Subject: [PATCH] Support Node.js 20 again (#3431)

* Support >= Node.js 20.4.0

* Improve the Node.js warning, ban 20.0 to 20.3

* Update

* Minor
---
 README.md         |  2 +-
 package-lock.json |  3 ++-
 package.json      |  3 ++-
 server/server.js  | 23 +++++++++++++++--------
 4 files changed, 20 insertions(+), 11 deletions(-)

diff --git a/README.md b/README.md
index c7aa4150..0e41652d 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,7 @@ Requirements:
   - ✅ Major Linux distros such as Debian, Ubuntu, CentOS, Fedora and ArchLinux etc.
   - ✅ Windows 10 (x64), Windows Server 2012 R2 (x64) or higher
   - ❌ Replit / Heroku
-- [Node.js](https://nodejs.org/en/download/) 14 / 16 / 18 (20 is not supported)
+- [Node.js](https://nodejs.org/en/download/) 14 / 16 / 18 / 20.4
 - [npm](https://docs.npmjs.com/cli/) >= 7
 - [Git](https://git-scm.com/downloads)
 - [pm2](https://pm2.keymetrics.io/) - For running Uptime Kuma in the background
diff --git a/package-lock.json b/package-lock.json
index 6b9b937b..9623da63 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -62,6 +62,7 @@
                 "qs": "~6.10.4",
                 "redbean-node": "~0.3.0",
                 "redis": "~4.5.1",
+                "semver": "^7.5.4",
                 "socket.io": "~4.6.1",
                 "socket.io-client": "~4.6.1",
                 "socks-proxy-agent": "6.1.1",
@@ -134,7 +135,7 @@
                 "whatwg-url": "~12.0.1"
             },
             "engines": {
-                "node": "14.* || 16.* || 18.*"
+                "node": "14.* || 16.* || 18.* || >= 20.4.0"
             }
         },
         "node_modules/@aashutoshrathi/word-wrap": {
diff --git a/package.json b/package.json
index 891cebd3..1526fbd3 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
         "url": "https://github.com/louislam/uptime-kuma.git"
     },
     "engines": {
-        "node": "14.* || 16.* || 18.*"
+        "node": "14 || 16 || 18 || >= 20.4.0"
     },
     "scripts": {
         "install-legacy": "npm install",
@@ -121,6 +121,7 @@
         "qs": "~6.10.4",
         "redbean-node": "~0.3.0",
         "redis": "~4.5.1",
+        "semver": "~7.5.4",
         "socket.io": "~4.6.1",
         "socket.io-client": "~4.6.1",
         "socks-proxy-agent": "6.1.1",
diff --git a/server/server.js b/server/server.js
index 9e34b4e7..d83b7da5 100644
--- a/server/server.js
+++ b/server/server.js
@@ -15,18 +15,25 @@ dayjs.extend(require("dayjs/plugin/customParseFormat"));
 require("dotenv").config();
 
 // Check Node.js Version
-const nodeVersion = parseInt(process.versions.node.split(".")[0]);
-const requiredVersion = 14;
+const nodeVersion = process.versions.node;
+
+// Get the required Node.js version from package.json
+const requiredNodeVersions = require("../package.json").engines.node;
+const bannedNodeVersions = " < 14 || 20.0.* || 20.1.* || 20.2.* || 20.3.* ";
 console.log(`Your Node.js version: ${nodeVersion}`);
 
-// See more: https://github.com/louislam/uptime-kuma/issues/3138
-if (nodeVersion >= 20) {
-    console.warn("\x1b[31m%s\x1b[0m", "Warning: Uptime Kuma is currently not stable on Node.js >= 20, please use Node.js 18.");
+const semver = require("semver");
+const requiredNodeVersionsComma = requiredNodeVersions.split("||").map((version) => version.trim()).join(", ");
+
+// Exit Uptime Kuma immediately if the Node.js version is banned
+if (semver.satisfies(nodeVersion, bannedNodeVersions)) {
+    console.error("\x1b[31m%s\x1b[0m", `Error: Your Node.js version: ${nodeVersion} is not supported, please upgrade your Node.js to ${requiredNodeVersionsComma}.`);
+    process.exit(-1);
 }
 
-if (nodeVersion < requiredVersion) {
-    console.error(`Error: Your Node.js version is not supported, please upgrade to Node.js >= ${requiredVersion}.`);
-    process.exit(-1);
+// Warning if the Node.js version is not in the support list, but it maybe still works
+if (!semver.satisfies(nodeVersion, requiredNodeVersions)) {
+    console.warn("\x1b[31m%s\x1b[0m", `Warning: Your Node.js version: ${nodeVersion} is not officially supported, please upgrade your Node.js to ${requiredNodeVersionsComma}.`);
 }
 
 const args = require("args-parser")(process.argv);