Compare commits

...

9 Commits

Author SHA1 Message Date
Louis Lam
77a31f1fbe WIP 2025-11-10 04:05:45 +08:00
Louis Lam
fb0b8b484f WIP 2025-11-10 04:04:39 +08:00
Louis Lam
b50d496e75 WIP 2025-11-10 03:10:39 +08:00
Louis Lam
fe1cd3f2da
Merge branch '3.0.X' into dev-better-auth 2025-11-10 03:08:50 +08:00
Louis Lam
ac5781d711
Update playwright from ~1.39.0 to ~1.56.1 (#6321) 2025-11-08 02:58:58 +08:00
Louis Lam
fa2bc8eda6
Merge branch '3.0.X' into dev-better-auth 2025-11-05 22:05:07 +08:00
Louis Lam
93fc8e463f
[3.0.0] Project Upgrade (#6310) 2025-11-05 21:54:55 +08:00
Louis Lam
492b8f51ad schema 2025-10-29 00:42:26 +08:00
Louis Lam
c515b6d043 wip 2025-10-25 12:24:17 +08:00
24 changed files with 895 additions and 676 deletions

View File

@ -162,6 +162,8 @@ module.exports = {
"jsdoc/require-param-type": "off", "jsdoc/require-param-type": "off",
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
"prefer-const": "off", "prefer-const": "off",
"@typescript-eslint/no-unused-vars": "warn",
"eqeqeq": "off",
} }
} }
] ]

View File

@ -5,11 +5,11 @@ name: Auto Test
on: on:
push: push:
branches: [ master, 1.23.X ] branches: [ master, 1.23.X, 3.0.X ]
paths-ignore: paths-ignore:
- '*.md' - '*.md'
pull_request: pull_request:
branches: [ master, 1.23.X ] branches: [ master, 1.23.X, 3.0.X ]
paths-ignore: paths-ignore:
- '*.md' - '*.md'
@ -23,11 +23,7 @@ jobs:
matrix: matrix:
os: [macos-latest, ubuntu-22.04, windows-latest, ARM64] os: [macos-latest, ubuntu-22.04, windows-latest, ARM64]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/ # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
node: [ 20, 24 ] node: [ 24, 25 ]
# Also test non-LTS, but only on Ubuntu.
include:
- os: ubuntu-22.04
node: 25
steps: steps:
- run: git config --global core.autocrlf false # Mainly for Windows - run: git config --global core.autocrlf false # Mainly for Windows
@ -44,28 +40,6 @@ jobs:
HEADLESS_TEST: 1 HEADLESS_TEST: 1
JUST_FOR_TEST: ${{ secrets.JUST_FOR_TEST }} 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: check-linters:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -73,10 +47,10 @@ jobs:
- run: git config --global core.autocrlf false # Mainly for Windows - run: git config --global core.autocrlf false # Mainly for Windows
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use Node.js 20 - name: Use Node.js 24
uses: actions/setup-node@v6 uses: actions/setup-node@v6
with: with:
node-version: 20 node-version: 24
- run: npm install - run: npm install
- run: npm run lint:prod - run: npm run lint:prod
@ -87,10 +61,10 @@ jobs:
- run: git config --global core.autocrlf false # Mainly for Windows - run: git config --global core.autocrlf false # Mainly for Windows
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use Node.js 20 - name: Use Node.js 24
uses: actions/setup-node@v6 uses: actions/setup-node@v6
with: with:
node-version: 20 node-version: 24
- run: npm install - run: npm install
- run: npx playwright install - run: npx playwright install
- run: npm run build - run: npm run build

View File

@ -7,6 +7,7 @@ on:
branches: branches:
- master - master
- 1.23.X - 1.23.X
- 3.0.X
workflow_dispatch: workflow_dispatch:
permissions: permissions:
@ -31,10 +32,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Use Node.js 20 - name: Use Node.js 24
uses: actions/setup-node@v6 uses: actions/setup-node@v6
with: with:
node-version: 20 node-version: 24
- name: Validate language JSON files - name: Validate language JSON files
run: node ./extra/check-lang-json.js run: node ./extra/check-lang-json.js

View File

@ -447,7 +447,7 @@ as easy as installing a mobile app.
- Easy to install for non-Docker users - 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 configuration and
- no extra effort required to get it running - no extra effort required to get it running
@ -639,7 +639,6 @@ repo to do that.
- amd64 - amd64
- arm64 - arm64
- armv7
### Docker Tags ### Docker Tags
@ -692,7 +691,7 @@ We have a few procedures we follow. These are documented here:
- <details><summary><b>Set up a Docker Builder</b> (click to expand)</summary> - <details><summary><b>Set up a Docker Builder</b> (click to expand)</summary>
<p> <p>
- amd64, armv7 using local. - amd64 using local.
- arm64 using remote arm64 cpu, as the emulator is too slow and can no longer - arm64 using remote arm64 cpu, as the emulator is too slow and can no longer
pass the `npm ci` command. 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. 3. Create a new builder.
```bash ```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 use kuma-builder
docker buildx inspect --bootstrap 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 - [ ] Check all tags is fine on
<https://hub.docker.com/r/louislam/uptime-kuma/tags> <https://hub.docker.com/r/louislam/uptime-kuma/tags>
- [ ] Try the Docker image with tag 1.X.X (Clean install / amd64 / arm64 / - [ ] Try the Docker image with tag 1.X.X (Clean install / amd64 / arm64)
armv7)
- [ ] Try clean installation with Node.js - [ ] Try clean installation with Node.js
</p> </p>

View File

@ -58,7 +58,7 @@ export default defineConfig({
// Run your local dev server before starting the tests. // Run your local dev server before starting the tests.
webServer: { 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, url,
reuseExistingServer: false, reuseExistingServer: false,
cwd: "../", cwd: "../",

View File

@ -0,0 +1,56 @@
/*
* The schema from: https://www.better-auth.com/docs/concepts/database#core-schema
*/
exports.up = function (knex) {
return knex.schema
.createTable("better_auth_user", (t) => {
t.string("id").primary();
t.string("name").notNullable();
t.string("email").notNullable();
t.boolean("emailVerified").notNullable();
t.string("image");
t.timestamp("createdAt").notNullable();
t.timestamp("updatedAt").notNullable();
})
.createTable("better_auth_session", (t) => {
t.string("id").primary();
t.string("userId").notNullable().references("id").inTable("user");
t.string("token").notNullable();
t.timestamp("expiresAt").notNullable();
t.string("ipAddress");
t.string("userAgent");
t.timestamp("createdAt").notNullable();
t.timestamp("updatedAt").notNullable();
})
.createTable("better_auth_account", (t) => {
t.string("id").primary();
t.string("userId").notNullable().references("id").inTable("user");
t.string("accountId").notNullable();
t.string("providerId").notNullable();
t.string("accessToken");
t.string("refreshToken");
t.timestamp("accessTokenExpiresAt");
t.timestamp("refreshTokenExpiresAt");
t.string("scope");
t.string("idToken");
t.string("password");
t.timestamp("createdAt").notNullable();
t.timestamp("updatedAt").notNullable();
})
.createTable("better_auth_verification", (t) => {
t.string("id").primary();
t.string("identifier").notNullable();
t.string("value").notNullable();
t.timestamp("expiresAt").notNullable();
t.timestamp("createdAt").notNullable();
t.timestamp("updatedAt").notNullable();
});
};
exports.down = function (knex) {
return knex.schema
.dropTableIfExists("better_auth_verification")
.dropTableIfExists("better_auth_account")
.dropTableIfExists("better_auth_session")
.dropTableIfExists("better_auth_user");
};

View File

@ -1,22 +1,15 @@
############################################ ############################################
# Build in Golang # 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 WORKDIR /app
ARG TARGETPLATFORM ARG TARGETPLATFORM
COPY ./extra/ ./extra/ 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 # Compile healthcheck.go
RUN apt update && \ RUN apt update && \
apt --yes --no-install-recommends install curl && \ 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 && \ apt --yes --no-install-recommends install nodejs && \
node ./extra/build-healthcheck.js $TARGETPLATFORM && \ node ./extra/build-healthcheck.js $TARGETPLATFORM && \
apt --yes remove nodejs apt --yes remove nodejs

View File

@ -1,5 +1,5 @@
# Download Apprise deb package # Download Apprise deb package
FROM node:22-bookworm-slim AS download-apprise FROM node:24-trixie-slim AS download-apprise
WORKDIR /app WORKDIR /app
COPY ./extra/download-apprise.mjs ./download-apprise.mjs COPY ./extra/download-apprise.mjs ./download-apprise.mjs
RUN apt update && \ RUN apt update && \
@ -9,7 +9,7 @@ RUN apt update && \
# Base Image (Slim) # Base Image (Slim)
# If the image changed, the second stage image should be changed too # 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 ARG TARGETPLATFORM
# Specify --no-install-recommends to skip unused dependencies, make the base much smaller! # Specify --no-install-recommends to skip unused dependencies, make the base much smaller!
@ -35,7 +35,6 @@ RUN apt update && \
apt --yes autoremove apt --yes autoremove
# apprise = for notifications (Install from the deb package, as the stable one is too old) (workaround for #4867) # 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) # python3-paho-mqtt (#4859)
# TODO: no idea how to delete the deb file after installation as it becomes a layer already # 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 COPY --from=download-apprise /app/apprise.deb ./apprise.deb
@ -47,7 +46,7 @@ RUN apt update && \
# Install cloudflared # Install cloudflared
RUN curl https://pkg.cloudflare.com/cloudflare-main.gpg --output /usr/share/keyrings/cloudflare-main.gpg && \ 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 update && \
apt install --yes --no-install-recommends cloudflared && \ apt install --yes --no-install-recommends cloudflared && \
cloudflared version && \ cloudflared version && \
@ -62,8 +61,7 @@ COPY ./docker/etc/sudoers /etc/sudoers
# Full Base Image # Full Base Image
# MariaDB, Chromium and fonts # MariaDB, Chromium and fonts
# Make sure to reuse the slim image here. Uncomment the above line if you want to build it from scratch. # 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:base3-slim AS base3
FROM louislam/uptime-kuma:base2-slim AS base2
ENV UPTIME_KUMA_ENABLE_EMBEDDED_MARIADB=1 ENV UPTIME_KUMA_ENABLE_EMBEDDED_MARIADB=1
RUN apt update && \ RUN apt update && \
apt --yes --no-install-recommends install chromium fonts-indic fonts-noto fonts-noto-cjk mariadb-server && \ apt --yes --no-install-recommends install chromium fonts-indic fonts-noto fonts-noto-cjk mariadb-server && \

View File

@ -3,7 +3,7 @@ version: '3.8'
services: services:
uptime-kuma: uptime-kuma:
container_name: uptime-kuma-dev container_name: uptime-kuma-dev
image: louislam/uptime-kuma:nightly2 image: louislam/uptime-kuma:nightly3
volumes: volumes:
#- ./data:/app/data #- ./data:/app/data
- ../server:/app/server - ../server:/app/server

View File

@ -1,16 +1,16 @@
ARG BASE_IMAGE=louislam/uptime-kuma:base2 ARG BASE_IMAGE=louislam/uptime-kuma:base3
############################################ ############################################
# Build in Golang # 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 # 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 # Build in Node.js
############################################ ############################################
FROM louislam/uptime-kuma:base2 AS build FROM louislam/uptime-kuma:base3 AS build
USER node USER node
WORKDIR /app WORKDIR /app
@ -59,7 +59,7 @@ USER node
############################################ ############################################
# Build an image for testing pr # Build an image for testing pr
############################################ ############################################
FROM louislam/uptime-kuma:base2 AS pr-test2 FROM louislam/uptime-kuma:base3 AS pr-test2
WORKDIR /app WORKDIR /app
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
@ -92,7 +92,7 @@ CMD ["npm", "run", "start-pr-test"]
############################################ ############################################
# Upload the artifact to Github # Upload the artifact to Github
############################################ ############################################
FROM louislam/uptime-kuma:base2 AS upload-artifact FROM louislam/uptime-kuma:base3 AS upload-artifact
WORKDIR / WORKDIR /
RUN apt update && \ RUN apt update && \
apt --yes install curl file apt --yes install curl file

View File

@ -1,5 +1,4 @@
const childProcess = require("child_process"); const childProcess = require("child_process");
const fs = require("fs");
const platform = process.argv[2]; const platform = process.argv[2];
if (!platform) { if (!platform) {
@ -7,21 +6,6 @@ if (!platform) {
process.exit(1); 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"); const output = childProcess.execSync("go build -x -o ./extra/healthcheck ./extra/healthcheck.go").toString("utf8");
console.log(output); console.log(output);

View File

@ -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();

View File

@ -50,13 +50,13 @@ execSync("node ./extra/beta/update-version.js");
buildDist(); buildDist();
// Build slim image (rootless) // 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) // Build full image (rootless)
buildImage(repoNames, [ "beta-rootless", ver(version, "rootless") ], "rootless"); buildImage(repoNames, [ "beta-rootless", ver(version, "rootless") ], "rootless");
// Build slim image // 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 // Build full image
buildImage(repoNames, [ "beta", version ], "release"); buildImage(repoNames, [ "beta", version ], "release");

View File

@ -40,16 +40,16 @@ execSync("node extra/update-version.js");
buildDist(); buildDist();
// Build slim image (rootless) // 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) // Build full image (rootless)
buildImage(repoNames, [ "2-rootless", ver(version, "rootless") ], "rootless"); buildImage(repoNames, [ "3-rootless", ver(version, "rootless") ], "rootless");
// Build slim image // 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 // Build full image
buildImage(repoNames, [ "next", "2", version ], "release"); buildImage(repoNames, [ "next", "3", version ], "release");
await pressAnyKey(); await pressAnyKey();

View File

@ -57,7 +57,7 @@ export function buildDist() {
* @param {string} platform Build platform * @param {string} platform Build platform
* @returns {void} * @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 = [ let args = [
"buildx", "buildx",
"build", "build",

View File

@ -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(" "));

743
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "uptime-kuma", "name": "uptime-kuma",
"version": "2.0.2", "version": "3.0.0-beta.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "uptime-kuma", "name": "uptime-kuma",
"version": "2.0.2", "version": "3.0.0-beta.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@grpc/grpc-js": "~1.8.22", "@grpc/grpc-js": "~1.8.22",
@ -17,6 +17,7 @@
"axios": "~0.30.0", "axios": "~0.30.0",
"badge-maker": "~3.3.1", "badge-maker": "~3.3.1",
"bcryptjs": "~2.4.3", "bcryptjs": "~2.4.3",
"better-auth": "~1.4.0-beta.18",
"chardet": "~1.4.0", "chardet": "~1.4.0",
"check-password-strength": "^2.0.5", "check-password-strength": "^2.0.5",
"cheerio": "~1.0.0-rc.12", "cheerio": "~1.0.0-rc.12",
@ -68,7 +69,7 @@
"password-hash": "~1.2.2", "password-hash": "~1.2.2",
"pg": "~8.11.3", "pg": "~8.11.3",
"pg-connection-string": "~2.6.2", "pg-connection-string": "~2.6.2",
"playwright-core": "~1.39.0", "playwright-core": "~1.56.1",
"prom-client": "~13.2.0", "prom-client": "~13.2.0",
"prometheus-api-metrics": "~3.2.1", "prometheus-api-metrics": "~3.2.1",
"promisify-child-process": "~4.1.2", "promisify-child-process": "~4.1.2",
@ -86,7 +87,9 @@
"tcp-ping": "~0.1.1", "tcp-ping": "~0.1.1",
"thirty-two": "~1.0.2", "thirty-two": "~1.0.2",
"tough-cookie": "~4.1.3", "tough-cookie": "~4.1.3",
"ws": "^8.13.0" "tsx": "~4.20.6",
"ws": "^8.13.0",
"zod": "~4.1.12"
}, },
"devDependencies": { "devDependencies": {
"@actions/github": "~6.0.0", "@actions/github": "~6.0.0",
@ -94,7 +97,7 @@
"@fortawesome/free-regular-svg-icons": "~5.15.4", "@fortawesome/free-regular-svg-icons": "~5.15.4",
"@fortawesome/free-solid-svg-icons": "~5.15.4", "@fortawesome/free-solid-svg-icons": "~5.15.4",
"@fortawesome/vue-fontawesome": "~3.0.0-5", "@fortawesome/vue-fontawesome": "~3.0.0-5",
"@playwright/test": "~1.39.0", "@playwright/test": "~1.56.1",
"@popperjs/core": "~2.10.2", "@popperjs/core": "~2.10.2",
"@testcontainers/hivemq": "^10.13.1", "@testcontainers/hivemq": "^10.13.1",
"@testcontainers/rabbitmq": "^10.13.2", "@testcontainers/rabbitmq": "^10.13.2",
@ -154,7 +157,7 @@
"whatwg-url": "~12.0.1" "whatwg-url": "~12.0.1"
}, },
"engines": { "engines": {
"node": ">= 20.4.0" "node": ">= 24.0.0"
} }
}, },
"node_modules/@actions/github": { "node_modules/@actions/github": {
@ -1276,6 +1279,46 @@
"dev": true, "dev": true,
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/@better-auth/core": {
"version": "1.4.0-beta.18",
"resolved": "https://registry.npmjs.org/@better-auth/core/-/core-1.4.0-beta.18.tgz",
"integrity": "sha512-2jukNv/JMsTbB49z/tr8cqmvNQgy/lfnoihYQsyNAJwtWhub0vQ/OCvAn0QTD1S+EH5ACqLQEQJDydSRWdGAwA==",
"dependencies": {
"@standard-schema/spec": "^1.0.0",
"zod": "^4.1.5"
},
"peerDependencies": {
"@better-auth/utils": "0.3.0",
"@better-fetch/fetch": "1.1.18",
"better-call": "1.0.26",
"jose": "^6.1.0",
"kysely": "^0.28.5",
"nanostores": "^1.0.1"
}
},
"node_modules/@better-auth/telemetry": {
"version": "1.4.0-beta.18",
"resolved": "https://registry.npmjs.org/@better-auth/telemetry/-/telemetry-1.4.0-beta.18.tgz",
"integrity": "sha512-IaakqUqzwzwp9kSzZbAnrQUIwHSkGXhV4ON1mmJOgZ3Yl+ti8/HcV+83RFZXPtThUs3C5h0Km6Q0t4M5LSr69A==",
"dependencies": {
"@better-auth/utils": "0.3.0",
"@better-fetch/fetch": "1.1.18"
},
"peerDependencies": {
"@better-auth/core": "1.4.0-beta.18"
}
},
"node_modules/@better-auth/utils": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@better-auth/utils/-/utils-0.3.0.tgz",
"integrity": "sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw==",
"license": "MIT"
},
"node_modules/@better-fetch/fetch": {
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/@better-fetch/fetch/-/fetch-1.1.18.tgz",
"integrity": "sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA=="
},
"node_modules/@csstools/css-parser-algorithms": { "node_modules/@csstools/css-parser-algorithms": {
"version": "2.7.1", "version": "2.7.1",
"resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.7.1.tgz", "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.7.1.tgz",
@ -1670,6 +1713,22 @@
"node": ">=12" "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": { "node_modules/@esbuild/netbsd-x64": {
"version": "0.21.5", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
@ -1687,6 +1746,22 @@
"node": ">=12" "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": { "node_modules/@esbuild/openbsd-x64": {
"version": "0.21.5", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
@ -1704,6 +1779,22 @@
"node": ">=12" "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": { "node_modules/@esbuild/sunos-x64": {
"version": "0.21.5", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
@ -2626,20 +2717,19 @@
} }
}, },
"node_modules/@playwright/test": { "node_modules/@playwright/test": {
"version": "1.39.0", "version": "1.56.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.39.0.tgz", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz",
"integrity": "sha512-3u1iFqgzl7zr004bGPYiN/5EZpRUSFddQBra8Rqll5N0/vfpqlP9I9EXqAoGacuAbX6c9Ulg/Cjqglp5VkK6UQ==", "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==",
"deprecated": "Please update to the latest version of Playwright to test up-to-date browsers.",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"playwright": "1.39.0" "playwright": "1.56.1"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
}, },
"engines": { "engines": {
"node": ">=16" "node": ">=18"
} }
}, },
"node_modules/@popperjs/core": { "node_modules/@popperjs/core": {
@ -3796,6 +3886,12 @@
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@standard-schema/spec": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
"integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
"license": "MIT"
},
"node_modules/@szmarczak/http-timer": { "node_modules/@szmarczak/http-timer": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz",
@ -5436,6 +5532,97 @@
"dev": true, "dev": true,
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/better-auth": {
"version": "1.4.0-beta.18",
"resolved": "https://registry.npmjs.org/better-auth/-/better-auth-1.4.0-beta.18.tgz",
"integrity": "sha512-cniYRN7KalxQwfGfEsGDrvivnAJ9OmcxaB4WMasWYTBuWPWg+ttLWLzWhWY2CUQfSRBzYK+Aao3lB2ppF6rs0Q==",
"license": "MIT",
"dependencies": {
"@better-auth/core": "1.4.0-beta.18",
"@better-auth/telemetry": "1.4.0-beta.18",
"@better-auth/utils": "0.3.0",
"@better-fetch/fetch": "1.1.18",
"@noble/ciphers": "^2.0.0",
"@noble/hashes": "^2.0.0",
"@standard-schema/spec": "^1.0.0",
"better-call": "1.0.26",
"defu": "^6.1.4",
"jose": "^6.1.0",
"kysely": "^0.28.5",
"nanostores": "^1.0.1",
"zod": "^4.1.5"
},
"peerDependenciesMeta": {
"@lynx-js/react": {
"optional": true
},
"@sveltejs/kit": {
"optional": true
},
"next": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
},
"solid-js": {
"optional": true
},
"svelte": {
"optional": true
},
"vue": {
"optional": true
}
}
},
"node_modules/better-auth/node_modules/@noble/ciphers": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.0.1.tgz",
"integrity": "sha512-xHK3XHPUW8DTAobU+G0XT+/w+JLM7/8k1UFdB5xg/zTFPnFCobhftzw8wl4Lw2aq/Rvir5pxfZV5fEazmeCJ2g==",
"license": "MIT",
"engines": {
"node": ">= 20.19.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/better-auth/node_modules/@noble/hashes": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.1.tgz",
"integrity": "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==",
"license": "MIT",
"engines": {
"node": ">= 20.19.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/better-auth/node_modules/jose": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jose/-/jose-6.1.0.tgz",
"integrity": "sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/panva"
}
},
"node_modules/better-call": {
"version": "1.0.26",
"resolved": "https://registry.npmjs.org/better-call/-/better-call-1.0.26.tgz",
"integrity": "sha512-/5AaTPC8IRXV5yWxpAI7eR2RNiGHq4q/mjBm9DiikIkmJhzuqO1Ub66oYYqJ3eBFF+6BfdtZFRnuW0me8T0Emg==",
"dependencies": {
"@better-auth/utils": "^0.3.0",
"@better-fetch/fetch": "^1.1.4",
"rou3": "^0.5.1",
"set-cookie-parser": "^2.7.1"
}
},
"node_modules/binary-extensions": { "node_modules/binary-extensions": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
@ -6967,6 +7154,12 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/defu": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz",
"integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
"license": "MIT"
},
"node_modules/delay": { "node_modules/delay": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz",
@ -9041,6 +9234,18 @@
"url": "https://github.com/sponsors/ljharb" "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": { "node_modules/getopts": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/getopts/-/getopts-2.3.0.tgz", "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.3.0.tgz",
@ -10617,6 +10822,15 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/kysely": {
"version": "0.28.8",
"resolved": "https://registry.npmjs.org/kysely/-/kysely-0.28.8.tgz",
"integrity": "sha512-QUOgl5ZrS9IRuhq5FvOKFSsD/3+IA6MLE81/bOOTRA/YQpKDza2sFdN5g6JCB9BOpqMJDGefLCQ9F12hRS13TA==",
"license": "MIT",
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/lazystream": { "node_modules/lazystream": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz",
@ -11594,6 +11808,21 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
} }
}, },
"node_modules/nanostores": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/nanostores/-/nanostores-1.0.1.tgz",
"integrity": "sha512-kNZ9xnoJYKg/AfxjrVL4SS0fKX++4awQReGqWnwTRHxeHGZ1FJFVgTqr/eMrNQdp0Tz7M7tG/TDaX8QfHDwVCw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"engines": {
"node": "^20.0.0 || >=22.0.0"
}
},
"node_modules/native-duplexpair": { "node_modules/native-duplexpair": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/native-duplexpair/-/native-duplexpair-1.0.0.tgz", "resolved": "https://registry.npmjs.org/native-duplexpair/-/native-duplexpair-1.0.0.tgz",
@ -12473,34 +12702,34 @@
} }
}, },
"node_modules/playwright": { "node_modules/playwright": {
"version": "1.39.0", "version": "1.56.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.39.0.tgz", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz",
"integrity": "sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw==", "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"playwright-core": "1.39.0" "playwright-core": "1.56.1"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
}, },
"engines": { "engines": {
"node": ">=16" "node": ">=18"
}, },
"optionalDependencies": { "optionalDependencies": {
"fsevents": "2.3.2" "fsevents": "2.3.2"
} }
}, },
"node_modules/playwright-core": { "node_modules/playwright-core": {
"version": "1.39.0", "version": "1.56.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.39.0.tgz", "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz",
"integrity": "sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw==", "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
"playwright-core": "cli.js" "playwright-core": "cli.js"
}, },
"engines": { "engines": {
"node": ">=16" "node": ">=18"
} }
}, },
"node_modules/pngjs": { "node_modules/pngjs": {
@ -13662,6 +13891,15 @@
"node": ">=4" "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": { "node_modules/responselike": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",
@ -13819,6 +14057,12 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/rou3": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/rou3/-/rou3-0.5.1.tgz",
"integrity": "sha512-OXMmJ3zRk2xeXFGfA3K+EOPHC5u7RDFG7lIOx0X1pdnhUkI8MdVrbV+sNsD80ElpUZ+MRHdyxPnFthq9VHs8uQ==",
"license": "MIT"
},
"node_modules/rtlcss": { "node_modules/rtlcss": {
"version": "3.5.0", "version": "3.5.0",
"resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-3.5.0.tgz", "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-3.5.0.tgz",
@ -14118,6 +14362,12 @@
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/set-cookie-parser": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
"integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
"license": "MIT"
},
"node_modules/set-function-length": { "node_modules/set-function-length": {
"version": "1.2.2", "version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@ -15588,6 +15838,448 @@
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD" "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": { "node_modules/tunnel": {
"version": "0.0.6", "version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
@ -16764,6 +17456,15 @@
"engines": { "engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0" "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"
}
} }
} }
} }

View File

@ -1,13 +1,13 @@
{ {
"name": "uptime-kuma", "name": "uptime-kuma",
"version": "2.0.2", "version": "3.0.0-beta.0",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/louislam/uptime-kuma.git" "url": "https://github.com/louislam/uptime-kuma.git"
}, },
"engines": { "engines": {
"node": ">= 20.4.0" "node": ">= 24.0.0"
}, },
"scripts": { "scripts": {
"lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .", "lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
@ -19,28 +19,24 @@
"lint:prod": "npm run lint:js-prod && npm run lint:style", "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\"", "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-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": "npm run start-server",
"start-server": "node server/server.js", "start-server": "tsx server/server.js",
"start-server-dev": "cross-env NODE_ENV=development node server/server.js", "start-server-dev": "cross-env NODE_ENV=development tsx server/server.js",
"start-server-dev:watch": "cross-env NODE_ENV=development node --watch 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", "build": "vite build --config ./config/vite.config.js",
"test": "npm run test-backend && npm run test-e2e", "test": "npm run test-backend && npm run test-e2e",
"test-with-build": "npm run build && npm test", "test-with-build": "npm run build && npm test",
"test-backend": "node test/test-backend.mjs", "test-backend": "cross-env TEST_BACKEND=1 node --import=tsx --test \"test/backend-test/**/*.js\"",
"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-e2e": "playwright test --config ./config/playwright.config.js", "test-e2e": "playwright test --config ./config/playwright.config.js",
"test-e2e-ui": "playwright test --config ./config/playwright.config.js --ui --ui-port=51063", "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-codegen": "playwright codegen localhost:3000 --save-storage=./private/e2e-auth.json",
"playwright-show-report": "playwright show-report ./private/playwright-report", "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", "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": "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,linux/arm/v7 -t louislam/uptime-kuma:base2-slim --target base2-slim . --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,linux/arm/v7 -t louislam/uptime-kuma:builder-go . --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:nightly2 --target nightly .", "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-test2 --target pr-test2 . --push", "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": "node extra/release/upload-artifacts.mjs",
"upload-artifacts-beta": "node extra/release/upload-artifacts-beta.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", "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", "git-remove-tag": "git tag -d",
"build-dist-and-restart": "npm run build && npm run start-server-dev", "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", "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", "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:nightly3",
"quick-run-nightly": "docker run --rm --env NODE_ENV=development -p 3001:3001 louislam/uptime-kuma:nightly2",
"start-dev-container": "cd docker && docker-compose -f docker-compose-dev.yml up --force-recreate", "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", "reset-migrate-aggregate-table-state": "node extra/reset-migrate-aggregate-table-state.js",
"generate-changelog": "node ./extra/generate-changelog.mjs" "generate-changelog": "node ./extra/generate-changelog.mjs"
}, },
@ -78,6 +71,7 @@
"axios": "~0.30.0", "axios": "~0.30.0",
"badge-maker": "~3.3.1", "badge-maker": "~3.3.1",
"bcryptjs": "~2.4.3", "bcryptjs": "~2.4.3",
"better-auth": "~1.4.0-beta.18",
"chardet": "~1.4.0", "chardet": "~1.4.0",
"check-password-strength": "^2.0.5", "check-password-strength": "^2.0.5",
"cheerio": "~1.0.0-rc.12", "cheerio": "~1.0.0-rc.12",
@ -121,6 +115,7 @@
"nanoid": "~3.3.4", "nanoid": "~3.3.4",
"net-snmp": "^3.11.2", "net-snmp": "^3.11.2",
"node-cloudflared-tunnel": "~1.0.9", "node-cloudflared-tunnel": "~1.0.9",
"node-radius-utils": "~1.2.0",
"nodemailer": "~6.9.13", "nodemailer": "~6.9.13",
"nostr-tools": "^2.10.4", "nostr-tools": "^2.10.4",
"notp": "~2.0.3", "notp": "~2.0.3",
@ -128,14 +123,13 @@
"password-hash": "~1.2.2", "password-hash": "~1.2.2",
"pg": "~8.11.3", "pg": "~8.11.3",
"pg-connection-string": "~2.6.2", "pg-connection-string": "~2.6.2",
"playwright-core": "~1.39.0", "playwright-core": "~1.56.1",
"prom-client": "~13.2.0", "prom-client": "~13.2.0",
"prometheus-api-metrics": "~3.2.1", "prometheus-api-metrics": "~3.2.1",
"promisify-child-process": "~4.1.2", "promisify-child-process": "~4.1.2",
"protobufjs": "~7.2.4", "protobufjs": "~7.2.4",
"qs": "~6.10.4", "qs": "~6.10.4",
"radius": "~1.1.4", "radius": "~1.1.4",
"node-radius-utils": "~1.2.0",
"redbean-node": "~0.3.0", "redbean-node": "~0.3.0",
"redis": "~4.5.1", "redis": "~4.5.1",
"semver": "~7.5.4", "semver": "~7.5.4",
@ -147,7 +141,9 @@
"tcp-ping": "~0.1.1", "tcp-ping": "~0.1.1",
"thirty-two": "~1.0.2", "thirty-two": "~1.0.2",
"tough-cookie": "~4.1.3", "tough-cookie": "~4.1.3",
"ws": "^8.13.0" "tsx": "~4.20.6",
"ws": "^8.13.0",
"zod": "~4.1.12"
}, },
"devDependencies": { "devDependencies": {
"@actions/github": "~6.0.0", "@actions/github": "~6.0.0",
@ -155,7 +151,7 @@
"@fortawesome/free-regular-svg-icons": "~5.15.4", "@fortawesome/free-regular-svg-icons": "~5.15.4",
"@fortawesome/free-solid-svg-icons": "~5.15.4", "@fortawesome/free-solid-svg-icons": "~5.15.4",
"@fortawesome/vue-fontawesome": "~3.0.0-5", "@fortawesome/vue-fontawesome": "~3.0.0-5",
"@playwright/test": "~1.39.0", "@playwright/test": "~1.56.1",
"@popperjs/core": "~2.10.2", "@popperjs/core": "~2.10.2",
"@testcontainers/hivemq": "^10.13.1", "@testcontainers/hivemq": "^10.13.1",
"@testcontainers/rabbitmq": "^10.13.2", "@testcontainers/rabbitmq": "^10.13.2",

55
server/better-auth.ts Normal file
View File

@ -0,0 +1,55 @@
import { betterAuth } from "better-auth";
import { DatabaseSync } from "node:sqlite";
import * as Database from "./database.js";
import { genSecret, log } from "../src/util";
import { createPool } from "mysql2/promise";
// Check if Database.initDataDir() has been called before using this function
if (!Database.dataDir) {
throw new Error("Database data directory is not initialized. Please call Database.initDataDir() before using auth.");
}
let database: DatabaseSync;
// Better Auth is not supported with knex, so we need to create a separate connection here
if (Database.dbConfig.type == "sqlite") {
log.debug("better-auth", "Initializing better-auth with SQLite database at", Database.sqlitePath);
database = new DatabaseSync(Database.sqlitePath);
} else if (Database.dbConfig.type == "mariadb") {
// TODO
} else if (Database.dbConfig.type == "embedded-mariadb") {
log.debug("better-auth", "Initializing better-auth with MariaDB database");
// TODO
}
export const auth = betterAuth({
database,
secret: getAuthSecret(),
trustedOrigins: [ "*" ],
emailAndPassword: {
enabled: true,
},
});
/**
* Get the authentication secret for better-auth
* @returns The authentication secret
*/
export function getAuthSecret() {
const env = process.env.UPTIME_KUMA_AUTH_SECRET;
if (env) {
return env;
}
if (!Database.dbConfig.authSecret) {
Database.dbConfig.authSecret = genSecret();
Database.writeDBConfig(Database.dbConfig);
}
return Database.dbConfig.authSecret;
}

View File

@ -3,6 +3,8 @@
* node "server/server.js" * node "server/server.js"
* DO NOT require("./server") in other modules, it likely creates circular dependency! * 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"); console.log("Welcome to Uptime Kuma");
// As the log function need to use dayjs, it should be very top // 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 args = require("args-parser")(process.argv);
const { sleep, log, getRandomInt, genSecret, isDev } = require("../src/util");
const config = require("./config"); const config = require("./config");
log.debug("server", "Arguments"); log.debug("server", "Arguments");
@ -187,6 +188,9 @@ let needSetup = false;
process.exit(1); process.exit(1);
} }
// Init Better Auth
const { auth } = await import("./better-auth");
// Database should be ready now // Database should be ready now
await server.initAfterDatabaseReady(); await server.initAfterDatabaseReady();
server.entryPage = await Settings.get("entryPage"); server.entryPage = await Settings.get("entryPage");

View File

@ -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;

View File

@ -242,7 +242,7 @@ class Logger {
* @param msg Message to write * @param msg Message to write
* @returns {void} * @returns {void}
*/ */
log(module: string, level: string, ...msg: unknown[]) { private log(module: string, level: string, ...msg: unknown[]) {
if (level === "DEBUG" && !isDev) { if (level === "DEBUG" && !isDev) {
return; return;
} }

View File

@ -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" });
}

View File

@ -1,9 +0,0 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"esModuleInterop": false
},
"files": [
"./src/util.ts"
]
}