diff --git a/.github/workflows/auto-test.yml b/.github/workflows/auto-test.yml index 46fe5d23f..a59286682 100644 --- a/.github/workflows/auto-test.yml +++ b/.github/workflows/auto-test.yml @@ -5,11 +5,11 @@ name: Auto Test on: push: - branches: [ master, 1.23.X ] + branches: [ master, 1.23.X, 3.0.X ] paths-ignore: - '*.md' pull_request: - branches: [ master, 1.23.X ] + branches: [ master, 1.23.X, 3.0.X ] paths-ignore: - '*.md' @@ -23,11 +23,7 @@ jobs: matrix: os: [macos-latest, ubuntu-22.04, windows-latest, ARM64] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - node: [ 20, 24 ] - # Also test non-LTS, but only on Ubuntu. - include: - - os: ubuntu-22.04 - node: 25 + node: [ 24, 25 ] steps: - run: git config --global core.autocrlf false # Mainly for Windows @@ -44,28 +40,6 @@ jobs: HEADLESS_TEST: 1 JUST_FOR_TEST: ${{ secrets.JUST_FOR_TEST }} - # As a lot of dev dependencies are not supported on ARMv7, we have to test it separately and just test if `npm ci --production` works - armv7-simple-test: - needs: [ ] - runs-on: ${{ matrix.os }} - timeout-minutes: 15 - if: ${{ github.repository == 'louislam/uptime-kuma' }} - strategy: - matrix: - os: [ ARMv7 ] - node: [ 20, 22 ] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - - steps: - - run: git config --global core.autocrlf false # Mainly for Windows - - uses: actions/checkout@v4 - - - name: Use Node.js ${{ matrix.node }} - uses: actions/setup-node@v6 - with: - node-version: ${{ matrix.node }} - - run: npm ci --production - check-linters: runs-on: ubuntu-latest @@ -73,10 +47,10 @@ jobs: - run: git config --global core.autocrlf false # Mainly for Windows - uses: actions/checkout@v4 - - name: Use Node.js 20 + - name: Use Node.js 24 uses: actions/setup-node@v6 with: - node-version: 20 + node-version: 24 - run: npm install - run: npm run lint:prod @@ -87,10 +61,10 @@ jobs: - run: git config --global core.autocrlf false # Mainly for Windows - uses: actions/checkout@v4 - - name: Use Node.js 20 + - name: Use Node.js 24 uses: actions/setup-node@v6 with: - node-version: 20 + node-version: 24 - run: npm install - run: npx playwright install - run: npm run build diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 4dff3689d..35c0c1901 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -7,6 +7,7 @@ on: branches: - master - 1.23.X + - 3.0.X workflow_dispatch: permissions: @@ -31,10 +32,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Use Node.js 20 + - name: Use Node.js 24 uses: actions/setup-node@v6 with: - node-version: 20 + node-version: 24 - name: Validate language JSON files run: node ./extra/check-lang-json.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e4cae2ad0..02ca8aa79 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -447,7 +447,7 @@ as easy as installing a mobile app. - Easy to install for non-Docker users - - no native build dependency is needed (for `x86_64`/`armv7`/`arm64`) + - no native build dependency is needed (for `x86_64`/`arm64`) - no extra configuration and - no extra effort required to get it running @@ -639,7 +639,6 @@ repo to do that. - amd64 - arm64 -- armv7 ### Docker Tags @@ -692,7 +691,7 @@ We have a few procedures we follow. These are documented here: -
Set up a Docker Builder (click to expand)

- - amd64, armv7 using local. + - amd64 using local. - arm64 using remote arm64 cpu, as the emulator is too slow and can no longer pass the `npm ci` command. @@ -707,7 +706,7 @@ We have a few procedures we follow. These are documented here: 3. Create a new builder. ```bash - docker buildx create --name kuma-builder --platform linux/amd64,linux/arm/v7 + docker buildx create --name kuma-builder --platform linux/amd64 docker buildx use kuma-builder docker buildx inspect --bootstrap ``` @@ -742,8 +741,7 @@ We have a few procedures we follow. These are documented here: - [ ] Check all tags is fine on - - [ ] Try the Docker image with tag 1.X.X (Clean install / amd64 / arm64 / - armv7) + - [ ] Try the Docker image with tag 1.X.X (Clean install / amd64 / arm64) - [ ] Try clean installation with Node.js

diff --git a/config/playwright.config.js b/config/playwright.config.js index 5c574eecc..be07af9d0 100644 --- a/config/playwright.config.js +++ b/config/playwright.config.js @@ -58,7 +58,7 @@ export default defineConfig({ // Run your local dev server before starting the tests. webServer: { - command: `node extra/remove-playwright-test-data.js && cross-env NODE_ENV=development node server/server.js --port=${port} --data-dir=./data/playwright-test`, + command: `node extra/remove-playwright-test-data.js && cross-env NODE_ENV=development node --import=tsx server/server.js --port=${port} --data-dir=./data/playwright-test`, url, reuseExistingServer: false, cwd: "../", diff --git a/docker/builder-go.dockerfile b/docker/builder-go.dockerfile index 3a9d78248..5a05391fe 100644 --- a/docker/builder-go.dockerfile +++ b/docker/builder-go.dockerfile @@ -1,22 +1,15 @@ ############################################ # Build in Golang -# Run npm run build-healthcheck-armv7 in the host first, another it will be super slow where it is building the armv7 healthcheck ############################################ -FROM golang:1-buster +FROM golang:1-trixie WORKDIR /app ARG TARGETPLATFORM COPY ./extra/ ./extra/ -## Switch to archive.debian.org -RUN sed -i '/^deb/s/^/#/' /etc/apt/sources.list \ - && echo "deb http://archive.debian.org/debian buster main contrib non-free" | tee -a /etc/apt/sources.list \ - && echo "deb http://archive.debian.org/debian-security buster/updates main contrib non-free" | tee -a /etc/apt/sources.list \ - && echo "deb http://archive.debian.org/debian buster-updates main contrib non-free" | tee -a /etc/apt/sources.list - # Compile healthcheck.go RUN apt update && \ apt --yes --no-install-recommends install curl && \ - curl -sL https://deb.nodesource.com/setup_18.x | bash && \ + curl -sL https://deb.nodesource.com/setup_24.x | bash && \ apt --yes --no-install-recommends install nodejs && \ node ./extra/build-healthcheck.js $TARGETPLATFORM && \ apt --yes remove nodejs diff --git a/docker/debian-base.dockerfile b/docker/debian-base.dockerfile index 10471af2a..59f883bf9 100644 --- a/docker/debian-base.dockerfile +++ b/docker/debian-base.dockerfile @@ -1,5 +1,5 @@ # Download Apprise deb package -FROM node:22-bookworm-slim AS download-apprise +FROM node:24-trixie-slim AS download-apprise WORKDIR /app COPY ./extra/download-apprise.mjs ./download-apprise.mjs RUN apt update && \ @@ -9,7 +9,7 @@ RUN apt update && \ # Base Image (Slim) # If the image changed, the second stage image should be changed too -FROM node:22-bookworm-slim AS base2-slim +FROM node:24-trixie-slim AS base3-slim ARG TARGETPLATFORM # Specify --no-install-recommends to skip unused dependencies, make the base much smaller! @@ -35,7 +35,6 @@ RUN apt update && \ apt --yes autoremove # apprise = for notifications (Install from the deb package, as the stable one is too old) (workaround for #4867) -# Switching to testing repo is no longer working, as the testing repo is not bookworm anymore. # python3-paho-mqtt (#4859) # TODO: no idea how to delete the deb file after installation as it becomes a layer already COPY --from=download-apprise /app/apprise.deb ./apprise.deb @@ -47,7 +46,7 @@ RUN apt update && \ # Install cloudflared RUN curl https://pkg.cloudflare.com/cloudflare-main.gpg --output /usr/share/keyrings/cloudflare-main.gpg && \ - echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared bookworm main' | tee /etc/apt/sources.list.d/cloudflared.list && \ + echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main' | tee /etc/apt/sources.list.d/cloudflared.list && \ apt update && \ apt install --yes --no-install-recommends cloudflared && \ cloudflared version && \ @@ -62,8 +61,7 @@ COPY ./docker/etc/sudoers /etc/sudoers # Full Base Image # MariaDB, Chromium and fonts # Make sure to reuse the slim image here. Uncomment the above line if you want to build it from scratch. -# FROM base2-slim AS base2 -FROM louislam/uptime-kuma:base2-slim AS base2 +FROM louislam/uptime-kuma:base3-slim AS base3 ENV UPTIME_KUMA_ENABLE_EMBEDDED_MARIADB=1 RUN apt update && \ apt --yes --no-install-recommends install chromium fonts-indic fonts-noto fonts-noto-cjk mariadb-server && \ diff --git a/docker/docker-compose-dev.yml b/docker/docker-compose-dev.yml index c66b24b58..e0deaba4d 100644 --- a/docker/docker-compose-dev.yml +++ b/docker/docker-compose-dev.yml @@ -3,7 +3,7 @@ version: '3.8' services: uptime-kuma: container_name: uptime-kuma-dev - image: louislam/uptime-kuma:nightly2 + image: louislam/uptime-kuma:nightly3 volumes: #- ./data:/app/data - ../server:/app/server diff --git a/docker/dockerfile b/docker/dockerfile index e2a301e7b..793cec1dd 100644 --- a/docker/dockerfile +++ b/docker/dockerfile @@ -1,16 +1,16 @@ -ARG BASE_IMAGE=louislam/uptime-kuma:base2 +ARG BASE_IMAGE=louislam/uptime-kuma:base3 ############################################ # Build in Golang -# Run npm run build-healthcheck-armv7 in the host first, otherwise it will be super slow where it is building the armv7 healthcheck + # Check file: builder-go.dockerfile ############################################ -FROM louislam/uptime-kuma:builder-go AS build_healthcheck +FROM louislam/uptime-kuma:builder-go3 AS build_healthcheck ############################################ # Build in Node.js ############################################ -FROM louislam/uptime-kuma:base2 AS build +FROM louislam/uptime-kuma:base3 AS build USER node WORKDIR /app @@ -59,7 +59,7 @@ USER node ############################################ # Build an image for testing pr ############################################ -FROM louislam/uptime-kuma:base2 AS pr-test2 +FROM louislam/uptime-kuma:base3 AS pr-test2 WORKDIR /app ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 @@ -92,7 +92,7 @@ CMD ["npm", "run", "start-pr-test"] ############################################ # Upload the artifact to Github ############################################ -FROM louislam/uptime-kuma:base2 AS upload-artifact +FROM louislam/uptime-kuma:base3 AS upload-artifact WORKDIR / RUN apt update && \ apt --yes install curl file diff --git a/extra/build-healthcheck.js b/extra/build-healthcheck.js index e4c8026ab..61c436d2b 100644 --- a/extra/build-healthcheck.js +++ b/extra/build-healthcheck.js @@ -1,5 +1,4 @@ const childProcess = require("child_process"); -const fs = require("fs"); const platform = process.argv[2]; if (!platform) { @@ -7,21 +6,6 @@ if (!platform) { process.exit(1); } -if (platform === "linux/arm/v7") { - console.log("Arch: armv7"); - if (fs.existsSync("./extra/healthcheck-armv7")) { - fs.renameSync("./extra/healthcheck-armv7", "./extra/healthcheck"); - console.log("Already built in the host, skip."); - process.exit(0); - } else { - console.log("prebuilt not found, it will be slow! You should execute `npm run build-healthcheck-armv7` before build."); - } -} else { - if (fs.existsSync("./extra/healthcheck-armv7")) { - fs.rmSync("./extra/healthcheck-armv7"); - } -} - const output = childProcess.execSync("go build -x -o ./extra/healthcheck ./extra/healthcheck.go").toString("utf8"); console.log(output); diff --git a/extra/healthcheck.js b/extra/healthcheck.js deleted file mode 100644 index c9391c410..000000000 --- a/extra/healthcheck.js +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ⚠️ ⚠️ ⚠️ ⚠️ Due to the weird issue in Portainer that the healthcheck script is still pointing to this script for unknown reason. - * IT CANNOT BE DROPPED, even though it looks like it is not used. - * See more: https://github.com/louislam/uptime-kuma/issues/2774#issuecomment-1429092359 - * - * ⚠️ Deprecated: Changed to healthcheck.go, it will be deleted in the future. - * This script should be run after a period of time (180s), because the server may need some time to prepare. - */ -const FBSD = /^freebsd/.test(process.platform); - -process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; - -let client; - -const sslKey = process.env.UPTIME_KUMA_SSL_KEY || process.env.SSL_KEY || undefined; -const sslCert = process.env.UPTIME_KUMA_SSL_CERT || process.env.SSL_CERT || undefined; - -if (sslKey && sslCert) { - client = require("https"); -} else { - client = require("http"); -} - -// If host is omitted, the server will accept connections on the unspecified IPv6 address (::) when IPv6 is available and the unspecified IPv4 address (0.0.0.0) otherwise. -// Dual-stack support for (::) -let hostname = process.env.UPTIME_KUMA_HOST; - -// Also read HOST if not *BSD, as HOST is a system environment variable in FreeBSD -if (!hostname && !FBSD) { - hostname = process.env.HOST; -} - -const port = parseInt(process.env.UPTIME_KUMA_PORT || process.env.PORT || 3001); - -let options = { - host: hostname || "127.0.0.1", - port: port, - timeout: 28 * 1000, -}; - -let request = client.request(options, (res) => { - console.log(`Health Check OK [Res Code: ${res.statusCode}]`); - if (res.statusCode === 302) { - process.exit(0); - } else { - process.exit(1); - } -}); - -request.on("error", function (err) { - console.error("Health Check ERROR"); - process.exit(1); -}); - -request.end(); diff --git a/extra/release/beta.mjs b/extra/release/beta.mjs index f629f2c3f..5a4a93c92 100644 --- a/extra/release/beta.mjs +++ b/extra/release/beta.mjs @@ -50,13 +50,13 @@ execSync("node ./extra/beta/update-version.js"); buildDist(); // Build slim image (rootless) -buildImage(repoNames, [ "beta-slim-rootless", ver(version, "slim-rootless") ], "rootless", "BASE_IMAGE=louislam/uptime-kuma:base2-slim"); +buildImage(repoNames, [ "beta-slim-rootless", ver(version, "slim-rootless") ], "rootless", "BASE_IMAGE=louislam/uptime-kuma:base3-slim"); // Build full image (rootless) buildImage(repoNames, [ "beta-rootless", ver(version, "rootless") ], "rootless"); // Build slim image -buildImage(repoNames, [ "beta-slim", ver(version, "slim") ], "release", "BASE_IMAGE=louislam/uptime-kuma:base2-slim"); +buildImage(repoNames, [ "beta-slim", ver(version, "slim") ], "release", "BASE_IMAGE=louislam/uptime-kuma:base3-slim"); // Build full image buildImage(repoNames, [ "beta", version ], "release"); diff --git a/extra/release/final.mjs b/extra/release/final.mjs index 73c5a4cab..5012445c3 100644 --- a/extra/release/final.mjs +++ b/extra/release/final.mjs @@ -40,16 +40,16 @@ execSync("node extra/update-version.js"); buildDist(); // Build slim image (rootless) -buildImage(repoNames, [ "2-slim-rootless", ver(version, "slim-rootless") ], "rootless", "BASE_IMAGE=louislam/uptime-kuma:base2-slim"); +buildImage(repoNames, [ "3-slim-rootless", ver(version, "slim-rootless") ], "rootless", "BASE_IMAGE=louislam/uptime-kuma:base3-slim"); // Build full image (rootless) -buildImage(repoNames, [ "2-rootless", ver(version, "rootless") ], "rootless"); +buildImage(repoNames, [ "3-rootless", ver(version, "rootless") ], "rootless"); // Build slim image -buildImage(repoNames, [ "next-slim", "2-slim", ver(version, "slim") ], "release", "BASE_IMAGE=louislam/uptime-kuma:base2-slim"); +buildImage(repoNames, [ "next-slim", "3-slim", ver(version, "slim") ], "release", "BASE_IMAGE=louislam/uptime-kuma:base3-slim"); // Build full image -buildImage(repoNames, [ "next", "2", version ], "release"); +buildImage(repoNames, [ "next", "3", version ], "release"); await pressAnyKey(); diff --git a/extra/release/lib.mjs b/extra/release/lib.mjs index e390ce820..8f563e8de 100644 --- a/extra/release/lib.mjs +++ b/extra/release/lib.mjs @@ -57,7 +57,7 @@ export function buildDist() { * @param {string} platform Build platform * @returns {void} */ -export function buildImage(repoNames, tags, target, buildArgs = "", dockerfile = "docker/dockerfile", platform = "linux/amd64,linux/arm64,linux/arm/v7") { +export function buildImage(repoNames, tags, target, buildArgs = "", dockerfile = "docker/dockerfile", platform = "linux/amd64,linux/arm64") { let args = [ "buildx", "build", diff --git a/extra/sort-contributors.js b/extra/sort-contributors.js deleted file mode 100644 index b60d191f6..000000000 --- a/extra/sort-contributors.js +++ /dev/null @@ -1,22 +0,0 @@ -const fs = require("fs"); - -// Read the file from private/sort-contributors.txt -const file = fs.readFileSync("private/sort-contributors.txt", "utf8"); - -// Convert to an array of lines -let lines = file.split("\n"); - -// Remove empty lines -lines = lines.filter((line) => line !== ""); - -// Remove duplicates -lines = [ ...new Set(lines) ]; - -// Remove @weblate and @UptimeKumaBot -lines = lines.filter((line) => line !== "@weblate" && line !== "@UptimeKumaBot" && line !== "@louislam"); - -// Sort the lines -lines = lines.sort(); - -// Output the lines, concat with " " -console.log(lines.join(" ")); diff --git a/package-lock.json b/package-lock.json index 420b7a923..30ecc8fdc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "uptime-kuma", - "version": "2.0.2", + "version": "3.0.0-beta.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "uptime-kuma", - "version": "2.0.2", + "version": "3.0.0-beta.0", "license": "MIT", "dependencies": { "@grpc/grpc-js": "~1.8.22", @@ -86,7 +86,9 @@ "tcp-ping": "~0.1.1", "thirty-two": "~1.0.2", "tough-cookie": "~4.1.3", - "ws": "^8.13.0" + "tsx": "~4.20.6", + "ws": "^8.13.0", + "zod": "^4.1.12" }, "devDependencies": { "@actions/github": "~6.0.0", @@ -154,7 +156,7 @@ "whatwg-url": "~12.0.1" }, "engines": { - "node": ">= 20.4.0" + "node": ">= 24.0.0" } }, "node_modules/@actions/github": { @@ -1670,6 +1672,22 @@ "node": ">=12" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/netbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", @@ -1687,6 +1705,22 @@ "node": ">=12" } }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/openbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", @@ -1704,6 +1738,22 @@ "node": ">=12" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", @@ -9041,6 +9091,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/getopts": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.3.0.tgz", @@ -13662,6 +13724,15 @@ "node": ">=4" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/responselike": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", @@ -15588,6 +15659,448 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tsx": { + "version": "4.20.6", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", + "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/tsx/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -16764,6 +17277,15 @@ "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } + }, + "node_modules/zod": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", + "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/package.json b/package.json index d9614df7f..764c4f3e8 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { "name": "uptime-kuma", - "version": "2.0.2", + "version": "3.0.0-beta.0", "license": "MIT", "repository": { "type": "git", "url": "https://github.com/louislam/uptime-kuma.git" }, "engines": { - "node": ">= 20.4.0" + "node": ">= 24.0.0" }, "scripts": { "lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .", @@ -19,28 +19,24 @@ "lint:prod": "npm run lint:js-prod && npm run lint:style", "dev": "concurrently -k -r \"wait-on tcp:3000 && npm run start-server-dev \" \"npm run start-frontend-dev\"", "start-frontend-dev": "cross-env NODE_ENV=development vite --host --config ./config/vite.config.js", - "start-frontend-devcontainer": "cross-env NODE_ENV=development DEVCONTAINER=1 vite --host --config ./config/vite.config.js", "start": "npm run start-server", - "start-server": "node server/server.js", - "start-server-dev": "cross-env NODE_ENV=development node server/server.js", - "start-server-dev:watch": "cross-env NODE_ENV=development node --watch server/server.js", + "start-server": "tsx server/server.js", + "start-server-dev": "cross-env NODE_ENV=development tsx server/server.js", + "start-server-dev:watch": "cross-env NODE_ENV=development tsx --watch server/server.js", "build": "vite build --config ./config/vite.config.js", "test": "npm run test-backend && npm run test-e2e", "test-with-build": "npm run build && npm test", - "test-backend": "node test/test-backend.mjs", - "test-backend-22": "cross-env TEST_BACKEND=1 node --test \"test/backend-test/**/*.js\"", - "test-backend-20": "cross-env TEST_BACKEND=1 node --test test/backend-test", + "test-backend": "cross-env TEST_BACKEND=1 node --import=tsx --test \"test/backend-test/**/*.js\"", "test-e2e": "playwright test --config ./config/playwright.config.js", "test-e2e-ui": "playwright test --config ./config/playwright.config.js --ui --ui-port=51063", "playwright-codegen": "playwright codegen localhost:3000 --save-storage=./private/e2e-auth.json", "playwright-show-report": "playwright show-report ./private/playwright-report", - "tsc": "tsc --project ./tsconfig-backend.json", "vite-preview-dist": "vite preview --host --config ./config/vite.config.js", - "build-docker-base": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base2 --target base2 . --push", - "build-docker-base-slim": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base2-slim --target base2-slim . --push", - "build-docker-builder-go": "docker buildx build -f docker/builder-go.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:builder-go . --push", - "build-docker-nightly-local": "npm run build && docker build -f docker/dockerfile -t louislam/uptime-kuma:nightly2 --target nightly .", - "build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test2 --target pr-test2 . --push", + "build-docker-base": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:base3 --target base3 . --push", + "build-docker-base-slim": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:base3-slim --target base3-slim . --push", + "build-docker-builder-go": "docker buildx build -f docker/builder-go.dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:builder-go3 . --push", + "build-docker-nightly-local": "npm run build && docker build -f docker/dockerfile -t louislam/uptime-kuma:nightly3 --target nightly .", + "build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test3 --target pr-test3 . --push", "upload-artifacts": "node extra/release/upload-artifacts.mjs", "upload-artifacts-beta": "node extra/release/upload-artifacts-beta.mjs", "setup": "git checkout 2.0.2 && npm ci --omit dev --no-audit && npm run download-dist", @@ -60,12 +56,9 @@ "git-remove-tag": "git tag -d", "build-dist-and-restart": "npm run build && npm run start-server-dev", "start-pr-test": "node extra/checkout-pr.mjs && npm install && npm run dev", - "build-healthcheck-armv7": "cross-env GOOS=linux GOARCH=arm GOARM=7 go build -x -o ./extra/healthcheck-armv7 ./extra/healthcheck.go", "deploy-demo-server": "node extra/deploy-demo-server.js", - "sort-contributors": "node extra/sort-contributors.js", - "quick-run-nightly": "docker run --rm --env NODE_ENV=development -p 3001:3001 louislam/uptime-kuma:nightly2", + "quick-run-nightly": "docker run --rm --env NODE_ENV=development -p 3001:3001 louislam/uptime-kuma:nightly3", "start-dev-container": "cd docker && docker-compose -f docker-compose-dev.yml up --force-recreate", - "rebase-pr-to-1.23.X": "node extra/rebase-pr.js 1.23.X", "reset-migrate-aggregate-table-state": "node extra/reset-migrate-aggregate-table-state.js", "generate-changelog": "node ./extra/generate-changelog.mjs" }, @@ -121,6 +114,7 @@ "nanoid": "~3.3.4", "net-snmp": "^3.11.2", "node-cloudflared-tunnel": "~1.0.9", + "node-radius-utils": "~1.2.0", "nodemailer": "~6.9.13", "nostr-tools": "^2.10.4", "notp": "~2.0.3", @@ -135,7 +129,6 @@ "protobufjs": "~7.2.4", "qs": "~6.10.4", "radius": "~1.1.4", - "node-radius-utils": "~1.2.0", "redbean-node": "~0.3.0", "redis": "~4.5.1", "semver": "~7.5.4", @@ -147,7 +140,9 @@ "tcp-ping": "~0.1.1", "thirty-two": "~1.0.2", "tough-cookie": "~4.1.3", - "ws": "^8.13.0" + "tsx": "~4.20.6", + "ws": "^8.13.0", + "zod": "~4.1.12" }, "devDependencies": { "@actions/github": "~6.0.0", diff --git a/server/server.js b/server/server.js index 207710a98..6d4149ee7 100644 --- a/server/server.js +++ b/server/server.js @@ -3,6 +3,8 @@ * node "server/server.js" * DO NOT require("./server") in other modules, it likely creates circular dependency! */ +import { genSecret, getRandomInt, isDev, log, sleep } from "../src/util"; + console.log("Welcome to Uptime Kuma"); // As the log function need to use dayjs, it should be very top @@ -37,7 +39,6 @@ if (!semver.satisfies(nodeVersion, requiredNodeVersions)) { } const args = require("args-parser")(process.argv); -const { sleep, log, getRandomInt, genSecret, isDev } = require("../src/util"); const config = require("./config"); log.debug("server", "Arguments"); diff --git a/src/util.js b/src/util.js deleted file mode 100644 index 9ceaaf064..000000000 --- a/src/util.js +++ /dev/null @@ -1,445 +0,0 @@ -"use strict"; -/*! -// Common Util for frontend and backend -// -// DOT NOT MODIFY util.js! -// Need to run "npm run tsc" to compile if there are any changes. -// -// Backend uses the compiled file util.js -// Frontend uses util.ts -*/ -var _a; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.CONSOLE_STYLE_FgPink = exports.CONSOLE_STYLE_FgBrown = exports.CONSOLE_STYLE_FgViolet = exports.CONSOLE_STYLE_FgLightBlue = exports.CONSOLE_STYLE_FgLightGreen = exports.CONSOLE_STYLE_FgOrange = exports.CONSOLE_STYLE_FgGray = exports.CONSOLE_STYLE_FgWhite = exports.CONSOLE_STYLE_FgCyan = exports.CONSOLE_STYLE_FgMagenta = exports.CONSOLE_STYLE_FgBlue = exports.CONSOLE_STYLE_FgYellow = exports.CONSOLE_STYLE_FgGreen = exports.CONSOLE_STYLE_FgRed = exports.CONSOLE_STYLE_FgBlack = exports.CONSOLE_STYLE_Hidden = exports.CONSOLE_STYLE_Reverse = exports.CONSOLE_STYLE_Blink = exports.CONSOLE_STYLE_Underscore = exports.CONSOLE_STYLE_Dim = exports.CONSOLE_STYLE_Bright = exports.CONSOLE_STYLE_Reset = exports.PING_PER_REQUEST_TIMEOUT_DEFAULT = exports.PING_PER_REQUEST_TIMEOUT_MAX = exports.PING_PER_REQUEST_TIMEOUT_MIN = exports.PING_COUNT_DEFAULT = exports.PING_COUNT_MAX = exports.PING_COUNT_MIN = exports.PING_GLOBAL_TIMEOUT_DEFAULT = exports.PING_GLOBAL_TIMEOUT_MAX = exports.PING_GLOBAL_TIMEOUT_MIN = exports.PING_PACKET_SIZE_DEFAULT = exports.PING_PACKET_SIZE_MAX = exports.PING_PACKET_SIZE_MIN = exports.MIN_INTERVAL_SECOND = exports.MAX_INTERVAL_SECOND = exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = exports.SQL_DATETIME_FORMAT = exports.SQL_DATE_FORMAT = exports.STATUS_PAGE_MAINTENANCE = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.MAINTENANCE = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isNode = exports.isDev = void 0; -exports.evaluateJsonQuery = exports.intHash = exports.localToUTC = exports.utcToLocal = exports.utcToISODateTime = exports.isoToUTCDateTime = exports.parseTimeFromTimeObject = exports.parseTimeObject = exports.getMaintenanceRelativeURL = exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log = exports.debug = exports.ucfirst = exports.sleep = exports.flipStatus = exports.badgeConstants = exports.CONSOLE_STYLE_BgGray = exports.CONSOLE_STYLE_BgWhite = exports.CONSOLE_STYLE_BgCyan = exports.CONSOLE_STYLE_BgMagenta = exports.CONSOLE_STYLE_BgBlue = exports.CONSOLE_STYLE_BgYellow = exports.CONSOLE_STYLE_BgGreen = exports.CONSOLE_STYLE_BgRed = exports.CONSOLE_STYLE_BgBlack = void 0; -const dayjs_1 = require("dayjs"); -const jsonata = require("jsonata"); -exports.isDev = process.env.NODE_ENV === "development"; -exports.isNode = typeof process !== "undefined" && ((_a = process === null || process === void 0 ? void 0 : process.versions) === null || _a === void 0 ? void 0 : _a.node); -const dayjs = (exports.isNode) ? require("dayjs") : dayjs_1.default; -exports.appName = "Uptime Kuma"; -exports.DOWN = 0; -exports.UP = 1; -exports.PENDING = 2; -exports.MAINTENANCE = 3; -exports.STATUS_PAGE_ALL_DOWN = 0; -exports.STATUS_PAGE_ALL_UP = 1; -exports.STATUS_PAGE_PARTIAL_DOWN = 2; -exports.STATUS_PAGE_MAINTENANCE = 3; -exports.SQL_DATE_FORMAT = "YYYY-MM-DD"; -exports.SQL_DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss"; -exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = "YYYY-MM-DD HH:mm"; -exports.MAX_INTERVAL_SECOND = 2073600; -exports.MIN_INTERVAL_SECOND = 20; -exports.PING_PACKET_SIZE_MIN = 1; -exports.PING_PACKET_SIZE_MAX = 65500; -exports.PING_PACKET_SIZE_DEFAULT = 56; -exports.PING_GLOBAL_TIMEOUT_MIN = 1; -exports.PING_GLOBAL_TIMEOUT_MAX = 300; -exports.PING_GLOBAL_TIMEOUT_DEFAULT = 10; -exports.PING_COUNT_MIN = 1; -exports.PING_COUNT_MAX = 100; -exports.PING_COUNT_DEFAULT = 1; -exports.PING_PER_REQUEST_TIMEOUT_MIN = 1; -exports.PING_PER_REQUEST_TIMEOUT_MAX = 60; -exports.PING_PER_REQUEST_TIMEOUT_DEFAULT = 2; -exports.CONSOLE_STYLE_Reset = "\x1b[0m"; -exports.CONSOLE_STYLE_Bright = "\x1b[1m"; -exports.CONSOLE_STYLE_Dim = "\x1b[2m"; -exports.CONSOLE_STYLE_Underscore = "\x1b[4m"; -exports.CONSOLE_STYLE_Blink = "\x1b[5m"; -exports.CONSOLE_STYLE_Reverse = "\x1b[7m"; -exports.CONSOLE_STYLE_Hidden = "\x1b[8m"; -exports.CONSOLE_STYLE_FgBlack = "\x1b[30m"; -exports.CONSOLE_STYLE_FgRed = "\x1b[31m"; -exports.CONSOLE_STYLE_FgGreen = "\x1b[32m"; -exports.CONSOLE_STYLE_FgYellow = "\x1b[33m"; -exports.CONSOLE_STYLE_FgBlue = "\x1b[34m"; -exports.CONSOLE_STYLE_FgMagenta = "\x1b[35m"; -exports.CONSOLE_STYLE_FgCyan = "\x1b[36m"; -exports.CONSOLE_STYLE_FgWhite = "\x1b[37m"; -exports.CONSOLE_STYLE_FgGray = "\x1b[90m"; -exports.CONSOLE_STYLE_FgOrange = "\x1b[38;5;208m"; -exports.CONSOLE_STYLE_FgLightGreen = "\x1b[38;5;119m"; -exports.CONSOLE_STYLE_FgLightBlue = "\x1b[38;5;117m"; -exports.CONSOLE_STYLE_FgViolet = "\x1b[38;5;141m"; -exports.CONSOLE_STYLE_FgBrown = "\x1b[38;5;130m"; -exports.CONSOLE_STYLE_FgPink = "\x1b[38;5;219m"; -exports.CONSOLE_STYLE_BgBlack = "\x1b[40m"; -exports.CONSOLE_STYLE_BgRed = "\x1b[41m"; -exports.CONSOLE_STYLE_BgGreen = "\x1b[42m"; -exports.CONSOLE_STYLE_BgYellow = "\x1b[43m"; -exports.CONSOLE_STYLE_BgBlue = "\x1b[44m"; -exports.CONSOLE_STYLE_BgMagenta = "\x1b[45m"; -exports.CONSOLE_STYLE_BgCyan = "\x1b[46m"; -exports.CONSOLE_STYLE_BgWhite = "\x1b[47m"; -exports.CONSOLE_STYLE_BgGray = "\x1b[100m"; -const consoleModuleColors = [ - exports.CONSOLE_STYLE_FgCyan, - exports.CONSOLE_STYLE_FgGreen, - exports.CONSOLE_STYLE_FgLightGreen, - exports.CONSOLE_STYLE_FgBlue, - exports.CONSOLE_STYLE_FgLightBlue, - exports.CONSOLE_STYLE_FgMagenta, - exports.CONSOLE_STYLE_FgOrange, - exports.CONSOLE_STYLE_FgViolet, - exports.CONSOLE_STYLE_FgBrown, - exports.CONSOLE_STYLE_FgPink, -]; -const consoleLevelColors = { - "INFO": exports.CONSOLE_STYLE_FgCyan, - "WARN": exports.CONSOLE_STYLE_FgYellow, - "ERROR": exports.CONSOLE_STYLE_FgRed, - "DEBUG": exports.CONSOLE_STYLE_FgGray, -}; -exports.badgeConstants = { - naColor: "#999", - defaultUpColor: "#66c20a", - defaultWarnColor: "#eed202", - defaultDownColor: "#c2290a", - defaultPendingColor: "#f8a306", - defaultMaintenanceColor: "#1747f5", - defaultPingColor: "blue", - defaultStyle: "flat", - defaultPingValueSuffix: "ms", - defaultPingLabelSuffix: "h", - defaultUptimeValueSuffix: "%", - defaultUptimeLabelSuffix: "h", - defaultCertExpValueSuffix: " days", - defaultCertExpLabelSuffix: "h", - defaultCertExpireWarnDays: "14", - defaultCertExpireDownDays: "7" -}; -function flipStatus(s) { - if (s === exports.UP) { - return exports.DOWN; - } - if (s === exports.DOWN) { - return exports.UP; - } - return s; -} -exports.flipStatus = flipStatus; -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} -exports.sleep = sleep; -function ucfirst(str) { - if (!str) { - return str; - } - const firstLetter = str.substr(0, 1); - return firstLetter.toUpperCase() + str.substr(1); -} -exports.ucfirst = ucfirst; -function debug(msg) { - exports.log.log("", "debug", msg); -} -exports.debug = debug; -class Logger { - constructor() { - this.hideLog = { - info: [], - warn: [], - error: [], - debug: [], - }; - if (typeof process !== "undefined" && process.env.UPTIME_KUMA_HIDE_LOG) { - const list = process.env.UPTIME_KUMA_HIDE_LOG.split(",").map(v => v.toLowerCase()); - for (const pair of list) { - const values = pair.split(/_(.*)/s); - if (values.length >= 2) { - this.hideLog[values[0]].push(values[1]); - } - } - this.debug("server", "UPTIME_KUMA_HIDE_LOG is set"); - this.debug("server", this.hideLog); - } - } - log(module, level, ...msg) { - if (level === "DEBUG" && !exports.isDev) { - return; - } - if (this.hideLog[level] && this.hideLog[level].includes(module.toLowerCase())) { - return; - } - module = module.toUpperCase(); - level = level.toUpperCase(); - let now; - if (dayjs.tz) { - now = dayjs.tz(new Date()).format(); - } - else { - now = dayjs().format(); - } - const levelColor = consoleLevelColors[level]; - const moduleColor = consoleModuleColors[intHash(module, consoleModuleColors.length)]; - let timePart; - let modulePart; - let levelPart; - if (exports.isNode) { - switch (level) { - case "DEBUG": - timePart = exports.CONSOLE_STYLE_FgGray + now + exports.CONSOLE_STYLE_Reset; - break; - default: - timePart = exports.CONSOLE_STYLE_FgCyan + now + exports.CONSOLE_STYLE_Reset; - break; - } - modulePart = "[" + moduleColor + module + exports.CONSOLE_STYLE_Reset + "]"; - levelPart = levelColor + `${level}:` + exports.CONSOLE_STYLE_Reset; - } - else { - timePart = now; - modulePart = `[${module}]`; - levelPart = `${level}:`; - } - switch (level) { - case "ERROR": - console.error(timePart, modulePart, levelPart, ...msg); - break; - case "WARN": - console.warn(timePart, modulePart, levelPart, ...msg); - break; - case "INFO": - console.info(timePart, modulePart, levelPart, ...msg); - break; - case "DEBUG": - if (exports.isDev) { - console.debug(timePart, modulePart, levelPart, ...msg); - } - break; - default: - console.log(timePart, modulePart, levelPart, ...msg); - break; - } - } - info(module, ...msg) { - this.log(module, "info", ...msg); - } - warn(module, ...msg) { - this.log(module, "warn", ...msg); - } - error(module, ...msg) { - this.log(module, "error", ...msg); - } - debug(module, ...msg) { - this.log(module, "debug", ...msg); - } - exception(module, exception, ...msg) { - let finalMessage = exception; - if (msg) { - finalMessage = `${msg}: ${exception}`; - } - this.log(module, "error", finalMessage); - } -} -exports.log = new Logger(); -function polyfill() { - if (!String.prototype.replaceAll) { - String.prototype.replaceAll = function (str, newStr) { - if (Object.prototype.toString.call(str).toLowerCase() === "[object regexp]") { - return this.replace(str, newStr); - } - return this.replace(new RegExp(str, "g"), newStr); - }; - } -} -exports.polyfill = polyfill; -class TimeLogger { - constructor() { - this.startTime = dayjs().valueOf(); - } - print(name) { - if (exports.isDev && process.env.TIMELOGGER === "1") { - console.log(name + ": " + (dayjs().valueOf() - this.startTime) + "ms"); - } - } -} -exports.TimeLogger = TimeLogger; -function getRandomArbitrary(min, max) { - return Math.random() * (max - min) + min; -} -exports.getRandomArbitrary = getRandomArbitrary; -function getRandomInt(min, max) { - min = Math.ceil(min); - max = Math.floor(max); - return Math.floor(Math.random() * (max - min + 1)) + min; -} -exports.getRandomInt = getRandomInt; -const getRandomBytes = ((typeof window !== "undefined" && window.crypto) - ? function () { - return (numBytes) => { - const randomBytes = new Uint8Array(numBytes); - for (let i = 0; i < numBytes; i += 65536) { - window.crypto.getRandomValues(randomBytes.subarray(i, i + Math.min(numBytes - i, 65536))); - } - return randomBytes; - }; - } - : function () { - return require("crypto").randomBytes; - })(); -function getCryptoRandomInt(min, max) { - const range = max - min; - if (range >= Math.pow(2, 32)) { - console.log("Warning! Range is too large."); - } - let tmpRange = range; - let bitsNeeded = 0; - let bytesNeeded = 0; - let mask = 1; - while (tmpRange > 0) { - if (bitsNeeded % 8 === 0) { - bytesNeeded += 1; - } - bitsNeeded += 1; - mask = mask << 1 | 1; - tmpRange = tmpRange >>> 1; - } - const randomBytes = getRandomBytes(bytesNeeded); - let randomValue = 0; - for (let i = 0; i < bytesNeeded; i++) { - randomValue |= randomBytes[i] << 8 * i; - } - randomValue = randomValue & mask; - if (randomValue <= range) { - return min + randomValue; - } - else { - return getCryptoRandomInt(min, max); - } -} -exports.getCryptoRandomInt = getCryptoRandomInt; -function genSecret(length = 64) { - let secret = ""; - const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - const charsLength = chars.length; - for (let i = 0; i < length; i++) { - secret += chars.charAt(getCryptoRandomInt(0, charsLength - 1)); - } - return secret; -} -exports.genSecret = genSecret; -function getMonitorRelativeURL(id) { - return "/dashboard/" + id; -} -exports.getMonitorRelativeURL = getMonitorRelativeURL; -function getMaintenanceRelativeURL(id) { - return "/maintenance/" + id; -} -exports.getMaintenanceRelativeURL = getMaintenanceRelativeURL; -function parseTimeObject(time) { - if (!time) { - return { - hours: 0, - minutes: 0, - }; - } - const array = time.split(":"); - if (array.length < 2) { - throw new Error("parseVueDatePickerTimeFormat: Invalid Time"); - } - const obj = { - hours: parseInt(array[0]), - minutes: parseInt(array[1]), - seconds: 0, - }; - if (array.length >= 3) { - obj.seconds = parseInt(array[2]); - } - return obj; -} -exports.parseTimeObject = parseTimeObject; -function parseTimeFromTimeObject(obj) { - if (!obj) { - return obj; - } - let result = ""; - result += obj.hours.toString().padStart(2, "0") + ":" + obj.minutes.toString().padStart(2, "0"); - if (obj.seconds) { - result += ":" + obj.seconds.toString().padStart(2, "0"); - } - return result; -} -exports.parseTimeFromTimeObject = parseTimeFromTimeObject; -function isoToUTCDateTime(input) { - return dayjs(input).utc().format(exports.SQL_DATETIME_FORMAT); -} -exports.isoToUTCDateTime = isoToUTCDateTime; -function utcToISODateTime(input) { - return dayjs.utc(input).toISOString(); -} -exports.utcToISODateTime = utcToISODateTime; -function utcToLocal(input, format = exports.SQL_DATETIME_FORMAT) { - return dayjs.utc(input).local().format(format); -} -exports.utcToLocal = utcToLocal; -function localToUTC(input, format = exports.SQL_DATETIME_FORMAT) { - return dayjs(input).utc().format(format); -} -exports.localToUTC = localToUTC; -function intHash(str, length = 10) { - let hash = 0; - for (let i = 0; i < str.length; i++) { - hash += str.charCodeAt(i); - } - return (hash % length + length) % length; -} -exports.intHash = intHash; -async function evaluateJsonQuery(data, jsonPath, jsonPathOperator, expectedValue) { - let response; - try { - response = JSON.parse(data); - } - catch (_a) { - response = (typeof data === "object" || typeof data === "number") && !Buffer.isBuffer(data) ? data : data.toString(); - } - try { - response = (jsonPath) ? await jsonata(jsonPath).evaluate(response) : response; - if (response === null || response === undefined) { - throw new Error("Empty or undefined response. Check query syntax and response structure"); - } - if (typeof response === "object" || response instanceof Date || typeof response === "function") { - throw new Error(`The post-JSON query evaluated response from the server is of type ${typeof response}, which cannot be directly compared to the expected value`); - } - let jsonQueryExpression; - switch (jsonPathOperator) { - case ">": - case ">=": - case "<": - case "<=": - jsonQueryExpression = `$number($.value) ${jsonPathOperator} $number($.expected)`; - break; - case "!=": - jsonQueryExpression = "$.value != $.expected"; - break; - case "==": - jsonQueryExpression = "$.value = $.expected"; - break; - case "contains": - jsonQueryExpression = "$contains($.value, $.expected)"; - break; - default: - throw new Error(`Invalid condition ${jsonPathOperator}`); - } - const expression = jsonata(jsonQueryExpression); - const status = await expression.evaluate({ - value: response.toString(), - expected: expectedValue.toString() - }); - if (status === undefined) { - throw new Error("Query evaluation returned undefined. Check query syntax and the structure of the response data"); - } - return { - status, - response - }; - } - catch (err) { - response = JSON.stringify(response); - response = (response && response.length > 50) ? `${response.substring(0, 100)}… (truncated)` : response; - throw new Error(`Error evaluating JSON query: ${err.message}. Response from server was: ${response}`); - } -} -exports.evaluateJsonQuery = evaluateJsonQuery; diff --git a/test/test-backend.mjs b/test/test-backend.mjs deleted file mode 100644 index e285f7804..000000000 --- a/test/test-backend.mjs +++ /dev/null @@ -1,12 +0,0 @@ -import * as childProcess from "child_process"; - -const version = parseInt(process.version.slice(1).split(".")[0]); - -/** - * Since Node.js 22 introduced a different "node --test" command with glob, we need to run different test commands based on the Node.js version. - */ -if (version < 22) { - childProcess.execSync("npm run test-backend-20", { stdio: "inherit" }); -} else { - childProcess.execSync("npm run test-backend-22", { stdio: "inherit" }); -} diff --git a/tsconfig-backend.json b/tsconfig-backend.json deleted file mode 100644 index 08be7e5bb..000000000 --- a/tsconfig-backend.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "esModuleInterop": false - }, - "files": [ - "./src/util.ts" - ] -}