Merge branch 'dev' into feat/cli

This commit is contained in:
Hintay 2025-02-04 22:54:51 +09:00
commit 8a7ed08619
No known key found for this signature in database
GPG key ID: 120FC7FF121F2F2D
69 changed files with 1233 additions and 623 deletions

View file

@ -7,7 +7,7 @@ tmp_dir = "tmp"
[build]
# Just plain old shell command. You could use `make` as well.
cmd = "CGO_ENABLED=1 go build -tags=jsoniter -ldflags=\"-X 'github.com/0xJacky/Nginx-UI/settings.buildTime=$(date +%s)'\" -v -o ./tmp/main ."
cmd = "CGO_ENABLED=1 go build -tags=jsoniter,unembed -ldflags=\"-X 'github.com/0xJacky/Nginx-UI/settings.buildTime=$(date +%s)'\" -v -o ./tmp/main ."
# Binary file yields from `cmd`.
bin = "tmp/main"
# Customize binary.

49
.devcontainer/Dockerfile Normal file
View file

@ -0,0 +1,49 @@
FROM mcr.microsoft.com/devcontainers/base:jammy
# Combine installation steps for Nginx and Go to avoid repetitive update/cleanup commands
RUN apt-get update && \
apt-get install -y --no-install-recommends curl gnupg2 ca-certificates lsb-release ubuntu-keyring jq && \
\
# Configure the Nginx repository
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor > /usr/share/keyrings/nginx-archive-keyring.gpg && \
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/mainline/ubuntu $(lsb_release -cs) nginx" \
> /etc/apt/sources.list.d/nginx.list && \
printf "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
> /etc/apt/preferences.d/99nginx && \
\
# Update package information and install Nginx
apt-get update && \
apt-get install -y --no-install-recommends nginx inotify-tools file && \
\
# Automatically retrieve the latest stable Go version and install it,
# download the appropriate binary based on system architecture (amd64 or arm64)
GO_VERSION=$(curl -sSL "https://golang.org/dl/?mode=json" | \
jq -r 'map(select(.stable)) | .[0].version' | sed 's/^go//') && \
ARCH=$(dpkg --print-architecture) && \
if [ "$ARCH" = "arm64" ]; then \
GO_ARCH=linux-arm64; \
else \
GO_ARCH=linux-amd64; \
fi && \
echo "Installing Go version: ${GO_VERSION} for architecture: ${GO_ARCH}" && \
curl -sSL "https://golang.org/dl/go${GO_VERSION}.${GO_ARCH}.tar.gz" -o go.tar.gz && \
rm -rf /usr/local/go && \
tar -C /usr/local -xzf go.tar.gz && \
rm go.tar.gz && \
\
# Remove jq and clean up to reduce image size
apt-get remove -y jq && \
apt-get autoremove -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
RUN cp -rp /etc/nginx /etc/nginx.orig
# Set PATH to include Go installation and default go install binary location
ENV PATH="/usr/local/go/bin:/root/go/bin:${PATH}"
# Install air with go install (requires Go 1.23 or higher)
RUN go install github.com/air-verse/air@latest
# set zsh as default shell
RUN chsh -s $(which zsh)

View file

@ -0,0 +1,44 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu
{
"name": "Ubuntu",
"dockerComposeFile": "docker-compose.yml",
"service": "nginx-ui",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
"shutdownAction": "stopCompose",
// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {
"installOhMyZsh": true
},
"ghcr.io/devcontainers/features/node:1.6.1": {}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "",
// Configure tool-specific properties.
"customizations": {
"vscode": {
"extensions": [
"antfu.iconify",
"antfu.unocss",
"github.copilot",
"golang.go",
"vue.volar",
"ms-azuretools.vscode-docker"
]
}
},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
"remoteUser": "root",
"overrideCommand": false,
"postStartCommand": "./.devcontainer/start.sh",
"mounts": [
"source=${localEnv:HOME}/.ssh,target=/root/.ssh,type=bind,consistency=cached"
]
}

View file

@ -0,0 +1,57 @@
services:
nginx-ui:
build: .
image: nginx-ui-dev
container_name: nginx-ui
volumes:
- ../..:/workspaces:cached
- ./go-path:/root/go
- ./data/nginx:/etc/nginx
command: sleep infinity
environment:
- NGINX_UI_CERT_CA_DIR=https://pebble:14000/dir
networks:
nginxui:
nginx-ui-2:
image: nginx-ui-dev
container_name: nginx-ui-2
volumes:
- ../..:/workspaces:cached
- ./data/nginx-ui-2/nginx:/etc/nginx
- ./data/nginx-ui-2/nginx-ui:/etc/nginx-ui
working_dir: /workspaces/nginx-ui
command: ./.devcontainer/node-supervisor.sh
depends_on:
- nginx-ui
networks:
nginxui:
pebble:
image: ghcr.io/letsencrypt/pebble:latest
volumes:
- ./pebble-test:/test
command: -config /test/config/pebble-config.json -strict -dnsserver challtestsrv:8053
ports:
- 14000:14000 # HTTPS ACME API
- 15000:15000 # HTTPS Management API
environment:
- PEBBLE_VA_NOSLEEP=1
- PEBBLE_VA_ALWAYS_VALID=1
networks:
nginxui:
challtestsrv:
image: ghcr.io/letsencrypt/pebble-challtestsrv:latest
command: -defaultIPv6 "" -defaultIPv4 challtestsrv
ports:
- 8055:8055 # HTTP Management API
networks:
nginxui:
casdoor:
image: casbin/casdoor-all-in-one
ports:
- 8001:8000
networks:
- nginxui
networks:
nginxui:

6
.devcontainer/init-nginx.sh Executable file
View file

@ -0,0 +1,6 @@
# init nginx config dir
if [ "$(ls -A /etc/nginx)" = "" ]; then
echo "Initialing Nginx config dir"
cp -rp /etc/nginx.orig/* /etc/nginx/
echo "Initialed Nginx config dir"
fi

View file

@ -0,0 +1,87 @@
#!/bin/bash
# Configurable variables
SOURCE_FILE=/workspaces/nginx-ui/tmp/main
TARGET_PATH=/usr/local/bin/nginx-ui
CONFIG_FILE=/etc/nginx-ui/app.ini
# init nginx
./.devcontainer/init-nginx.sh
LOG_PREFIX="[Supervisor]"
# Debug initial state
echo "$LOG_PREFIX Starting supervisor with:"
echo "$LOG_PREFIX SOURCE_FILE: $SOURCE_FILE"
echo "$LOG_PREFIX TARGET_PATH: $TARGET_PATH"
echo "$LOG_PREFIX CONFIG_FILE: $CONFIG_FILE"
# Wait for initial file creation
while [[ ! -f "$SOURCE_FILE" ]]; do
echo "$LOG_PREFIX Waiting for $SOURCE_FILE to be created..."
sleep 1
done
# Initial copy and start
echo "$LOG_PREFIX Initial file detected, starting service..."
cp -fv "$SOURCE_FILE" "$TARGET_PATH"
chmod +x "$TARGET_PATH"
pkill -x nginx-ui || echo "$LOG_PREFIX No existing process to kill"
nohup "$TARGET_PATH" -config "$CONFIG_FILE" > /proc/1/fd/1 2>&1 &
# Use proper field separation for inotify output
inotifywait -m -e close_write,moved_to,create,delete \
--format "%T|%w%f|%e" \
--timefmt "%F-%H:%M:%S" \
"$(dirname "$SOURCE_FILE")" |
while IFS='|' read -r TIME FILE EVENT; do
echo "$LOG_PREFIX [${TIME}] Event: ${EVENT} - ${FILE}"
# Handle atomic save operations
if [[ "$FILE" =~ .*-tmp-umask$ ]] || [[ "$EVENT" == "DELETE" ]]; then
echo "$LOG_PREFIX Detected build intermediate file, checking main..."
sleep 0.3 # Allow atomic replace completion
if [[ -f "$SOURCE_FILE" ]]; then
echo "$LOG_PREFIX Valid main file detected after build"
FILE="$SOURCE_FILE"
else
echo "$LOG_PREFIX Main file missing after build operation"
continue
fi
fi
if [[ "$FILE" == "$SOURCE_FILE" ]]; then
# Stability checks
echo "$LOG_PREFIX File metadata:"
ls -l "$FILE"
file "$FILE"
# Wait for file stability with retries
retries=5
while ((retries-- > 0)); do
if file "$FILE" | grep -q "executable"; then
break
fi
echo "$LOG_PREFIX Waiting for valid executable (${retries} retries left)..."
sleep 1
done
if ((retries <= 0)); then
echo "$LOG_PREFIX ERROR: File validation failed after 5 retries"
continue
fi
# Copy and restart service
echo "$LOG_PREFIX Updating service..."
cp -fv "$FILE" "$TARGET_PATH"
chmod +x "$TARGET_PATH"
echo "$LOG_PREFIX Killing existing process..."
pkill -x nginx-ui || echo "$LOG_PREFIX No process to kill"
echo "$LOG_PREFIX Starting new process..."
nohup "$TARGET_PATH" -config "$CONFIG_FILE" > /proc/1/fd/1 2>&1 &
echo "$LOG_PREFIX Restart complete. New PID: $(pgrep nginx-ui)"
fi
done

View file

@ -0,0 +1,25 @@
# certs/
This directory contains a CA certificate (`pebble.minica.pem`) and a private key
(`pebble.minica.key.pem`) that are used to issue a end-entity certificate (See
`certs/localhost`) for the Pebble HTTPS server.
To get your **testing code** to use Pebble without HTTPS errors you should
configure your ACME client to trust the `pebble.minica.pem` CA certificate. Your
ACME client should offer a runtime option to specify a list of root CAs that you
can configure to include the `pebble.minica.pem` file.
**Do not** add this CA certificate to the system trust store or in production
code!!! The CA's private key is **public** and anyone can use it to issue
certificates that will be trusted by a system with the Pebble CA in the trust
store.
To re-create all of the Pebble certificates run:
minica -ca-cert pebble.minica.pem \
-ca-key pebble.minica.key.pem \
-domains localhost,pebble \
-ip-addresses 127.0.0.1
From the `test/certs/` directory after [installing
MiniCA](https://github.com/jsha/minica#installation)

View file

@ -0,0 +1,5 @@
# certs/localhost
This directory contains an end-entity (leaf) certificate (`cert.pem`) and
a private key (`key.pem`) for the Pebble HTTPS server. It includes `127.0.0.1`
as an IP address SAN, and `[localhost, pebble]` as DNS SANs.

View file

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDGzCCAgOgAwIBAgIIbEfayDFsBtwwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE
AxMVbWluaWNhIHJvb3QgY2EgMjRlMmRiMCAXDTE3MTIwNjE5NDIxMFoYDzIxMDcx
MjA2MTk0MjEwWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQCbFMW3DXXdErvQf2lCZ0qz0DGEWadDoF0O2neM5mVa
VQ7QGW0xc5Qwvn3Tl62C0JtwLpF0pG2BICIN+DHdVaIUwkf77iBS2doH1I3waE1I
8GkV9JrYmFY+j0dA1SwBmqUZNXhLNwZGq1a91nFSI59DZNy/JciqxoPX2K++ojU2
FPpuXe2t51NmXMsszpa+TDqF/IeskA9A/ws6UIh4Mzhghx7oay2/qqj2IIPjAmJj
i73kdUvtEry3wmlkBvtVH50+FscS9WmPC5h3lDTk5nbzSAXKuFusotuqy3XTgY5B
PiRAwkZbEY43JNfqenQPHo7mNTt29i+NVVrBsnAa5ovrAgMBAAGjYzBhMA4GA1Ud
DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0T
AQH/BAIwADAiBgNVHREEGzAZgglsb2NhbGhvc3SCBnBlYmJsZYcEfwAAATANBgkq
hkiG9w0BAQsFAAOCAQEAYIkXff8H28KS0KyLHtbbSOGU4sujHHVwiVXSATACsNAE
D0Qa8hdtTQ6AUqA6/n8/u1tk0O4rPE/cTpsM3IJFX9S3rZMRsguBP7BSr1Lq/XAB
7JP/CNHt+Z9aKCKcg11wIX9/B9F7pyKM3TdKgOpqXGV6TMuLjg5PlYWI/07lVGFW
/mSJDRs8bSCFmbRtEqc4lpwlrpz+kTTnX6G7JDLfLWYw/xXVqwFfdengcDTHCc8K
wtgGq/Gu6vcoBxIO3jaca+OIkMfxxXmGrcNdseuUCa3RMZ8Qy03DqGu6Y6XQyK4B
W8zIG6H9SVKkAznM2yfYhW8v2ktcaZ95/OBHY97ZIw==
-----END CERTIFICATE-----

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAmxTFtw113RK70H9pQmdKs9AxhFmnQ6BdDtp3jOZlWlUO0Blt
MXOUML5905etgtCbcC6RdKRtgSAiDfgx3VWiFMJH++4gUtnaB9SN8GhNSPBpFfSa
2JhWPo9HQNUsAZqlGTV4SzcGRqtWvdZxUiOfQ2TcvyXIqsaD19ivvqI1NhT6bl3t
redTZlzLLM6Wvkw6hfyHrJAPQP8LOlCIeDM4YIce6Gstv6qo9iCD4wJiY4u95HVL
7RK8t8JpZAb7VR+dPhbHEvVpjwuYd5Q05OZ280gFyrhbrKLbqst104GOQT4kQMJG
WxGONyTX6np0Dx6O5jU7dvYvjVVawbJwGuaL6wIDAQABAoIBAGW9W/S6lO+DIcoo
PHL+9sg+tq2gb5ZzN3nOI45BfI6lrMEjXTqLG9ZasovFP2TJ3J/dPTnrwZdr8Et/
357YViwORVFnKLeSCnMGpFPq6YEHj7mCrq+YSURjlRhYgbVPsi52oMOfhrOIJrEG
ZXPAwPRi0Ftqu1omQEqz8qA7JHOkjB2p0i2Xc/uOSJccCmUDMlksRYz8zFe8wHuD
XvUL2k23n2pBZ6wiez6Xjr0wUQ4ESI02x7PmYgA3aqF2Q6ECDwHhjVeQmAuypMF6
IaTjIJkWdZCW96pPaK1t+5nTNZ+Mg7tpJ/PRE4BkJvqcfHEOOl6wAE8gSk5uVApY
ZRKGmGkCgYEAzF9iRXYo7A/UphL11bR0gqxB6qnQl54iLhqS/E6CVNcmwJ2d9pF8
5HTfSo1/lOXT3hGV8gizN2S5RmWBrc9HBZ+dNrVo7FYeeBiHu+opbX1X/C1HC0m1
wJNsyoXeqD1OFc1WbDpHz5iv4IOXzYdOdKiYEcTv5JkqE7jomqBLQk8CgYEAwkG/
rnwr4ThUo/DG5oH+l0LVnHkrJY+BUSI33g3eQ3eM0MSbfJXGT7snh5puJW0oXP7Z
Gw88nK3Vnz2nTPesiwtO2OkUVgrIgWryIvKHaqrYnapZHuM+io30jbZOVaVTMR9c
X/7/d5/evwXuP7p2DIdZKQKKFgROm1XnhNqVgaUCgYBD/ogHbCR5RVsOVciMbRlG
UGEt3YmUp/vfMuAsKUKbT2mJM+dWHVlb+LZBa4pC06QFgfxNJi/aAhzSGvtmBEww
xsXbaceauZwxgJfIIUPfNZCMSdQVIVTi2Smcx6UofBz6i/Jw14MEwlvhamaa7qVf
kqflYYwelga1wRNCPopLaQKBgQCWsZqZKQqBNMm0Q9yIhN+TR+2d7QFjqeePoRPl
1qxNejhq25ojE607vNv1ff9kWUGuoqSZMUC76r6FQba/JoNbefI4otd7x/GzM9uS
8MHMJazU4okwROkHYwgLxxkNp6rZuJJYheB4VDTfyyH/ng5lubmY7rdgTQcNyZ5I
majRYQKBgAMKJ3RlII0qvAfNFZr4Y2bNIq+60Z+Qu2W5xokIHCFNly3W1XDDKGFe
CCPHSvQljinke3P9gPt2HVdXxcnku9VkTti+JygxuLkVg7E0/SWwrWfGsaMJs+84
fK+mTZay2d3v24r9WKEKwLykngYPyZw5+BdWU0E+xx5lGUd3U4gG
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAuVoGTaFSWp3Y+N5JC8lOdL8wmWpaM73UaNzhYiqA7ZqijzVk
TTtoQvQFDcUwyXKOdWHONrv1ld3z224Us504jjlbZwI5uoquCOZ2WJbRhmXrRgzk
Fq+/MtoFmPkhtO/DLjjtocgyIirVXN8Yl2APvB5brvRfCm6kktYeecsWfW/O3ikf
gdM7tmocwQiBypiloHOjdd5e2g8cWNw+rqvILSUVNLaLpsi23cxnLqVb424wz9dZ
5dO0REg1gSxtf4N5LSb6iGuAVoFNhzIeKzQ+svDg9x8tx/DGOghJS/jDgmxSY1qo
bTsXhcmWVfat5GJ5PQgLkCSjBBrjeBlOrc4VtQIDAQABAoIBAQCAoRoou6C0ZEDU
DScyN8TrvlcS0LzClaWYFFmRT5/jxOG1cr8l3elwNXpgYQ2Hb6mvim2ajHxVQg/e
oxlYwO4jvWhSJzg63c0DPjS5LAlCNO6+0Wlk2RheSPGDhLlAoPeZ10YKdS1dis5B
Qk4Fl1O0IHlOBCcEzV4GzPOfYDI+X6/f4xY7qz1s+CgoIxjIeiG+1/WpZQpYhobY
7CfSDdYDKtksXi7iQkc5earUAHBqZ1gQTq6e5LVm9AjRzENhMctFgcPs5zOjp2ak
PluixrA8LTAfu9wQzvxDkPl0UarZVxCerw6nlAziILpQ+U6PtoPZj49VpntTc+cq
1qjzkbhBAoGBANElJmFWY2X6LgBpszeqt0ZOSbkFg2bC0wHCJrMlRzUMEn83w9e8
Z2Fqml9eCC5qxJcyxWDVQeoAX6090m0qgP8xNmGdafcVic2cUlrqtkqhhst2OHCO
MCQEB7cdsjiidNNrOgLbQ3i1bYID8BVLf/TDhEbRgvTewDaz6XPdoSIRAoGBAOLg
RuOec5gn50SrVycx8BLFO8AXjXojpZb1Xg26V5miz1IavSfDcgae/699ppSz+UWi
jGMFr/PokY2JxDVs3PyQLu7ahMzyFHr16Agvp5g5kq056XV+uI/HhqLHOWSQ09DS
1Vrj7FOYpKRzge3/AC7ty9Vr35uMiebpm4/CLFVlAoGALnsIJZfSbWaFdLgJCXUa
WDir77/G7T6dMIXanfPJ+IMfVUCqeLa5bxAHEOzP+qjl2giBjzy18nB00warTnGk
y5I/WMBoPW5++sAkGWqSatGtKGi0sGcZUdfHcy3ZXvbT6eyprtrWCuyfUsbXQ5RM
8rPFIQwNA6jBpSak2ohF+FECgYEAn+6IKncNd6pRfnfmdSvf1+uPxkcUJZCxb2xC
xByjGhvKWE+fHkPJwt8c0SIbZuJEC5Gds0RUF/XPfV4roZm/Yo9ldl02lp7kTxXA
XtzxIP8c5d5YM8qD4l8+Csu0Kq9pkeC+JFddxkRpc8A1TIehInPhZ+6mb6mvoMb3
MW0pAX0CgYATT74RYuIYWZvx0TK4ZXIKTw2i6HObLF63Y6UwyPXXdEVie/ToYRNH
JIxE1weVpHvnHZvVD6D3yGk39ZsCIt31VvKpatWXlWBm875MbBc6kuIGsYT+mSSj
y9TXaE89E5zfL27nZe15QLJ+Xw8Io6PMLZ/jtC5TYoEixSZ9J8v6HA==
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDCTCCAfGgAwIBAgIIJOLbes8sTr4wDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE
AxMVbWluaWNhIHJvb3QgY2EgMjRlMmRiMCAXDTE3MTIwNjE5NDIxMFoYDzIxMTcx
MjA2MTk0MjEwWjAgMR4wHAYDVQQDExVtaW5pY2Egcm9vdCBjYSAyNGUyZGIwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5WgZNoVJandj43kkLyU50vzCZ
alozvdRo3OFiKoDtmqKPNWRNO2hC9AUNxTDJco51Yc42u/WV3fPbbhSznTiOOVtn
Ajm6iq4I5nZYltGGZetGDOQWr78y2gWY+SG078MuOO2hyDIiKtVc3xiXYA+8Hluu
9F8KbqSS1h55yxZ9b87eKR+B0zu2ahzBCIHKmKWgc6N13l7aDxxY3D6uq8gtJRU0
toumyLbdzGcupVvjbjDP11nl07RESDWBLG1/g3ktJvqIa4BWgU2HMh4rND6y8OD3
Hy3H8MY6CElL+MOCbFJjWqhtOxeFyZZV9q3kYnk9CAuQJKMEGuN4GU6tzhW1AgMB
AAGjRTBDMA4GA1UdDwEB/wQEAwIChDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB
BQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsFAAOCAQEAF85v
d40HK1ouDAtWeO1PbnWfGEmC5Xa478s9ddOd9Clvp2McYzNlAFfM7kdcj6xeiNhF
WPIfaGAi/QdURSL/6C1KsVDqlFBlTs9zYfh2g0UXGvJtj1maeih7zxFLvet+fqll
xseM4P9EVJaQxwuK/F78YBt0tCNfivC6JNZMgxKF59h0FBpH70ytUSHXdz7FKwix
Mfn3qEb9BXSk0Q3prNV5sOV3vgjEtB4THfDxSz9z3+DepVnW3vbbqwEbkXdk3j82
2muVldgOUgTwK8eT+XdofVdntzU/kzygSAtAQwLJfn51fS1GvEcYGBc1bDryIqmF
p9BI7gVKtWSZYegicA==
-----END CERTIFICATE-----

View file

@ -0,0 +1,26 @@
{
"plan": {
"actions": [
"newAccount",
"newOrder",
"fulfillOrder",
"finalizeOrder"
],
"rate": 10,
"runtime": "10s",
"rateDelta": "1/10s"
},
"directoryURL": "https://localhost:14000/dir",
"domainBase": "com",
"challengeStrategy": "random",
"httpOneAddrs": [":5002"],
"tlsAlpnOneAddrs": [":5001"],
"dnsAddrs": [":8053"],
"fakeDNS": "127.0.0.1",
"regKeySize": 2048,
"certKeySize": 2048,
"regEmail": "loadtesting@letsencrypt.org",
"maxRegs": 20,
"maxNamesPerCert": 20,
"dontSaveState": true
}

View file

@ -0,0 +1,22 @@
{
"pebble": {
"listenAddress": "0.0.0.0:14000",
"managementListenAddress": "0.0.0.0:15000",
"certificate": "/test/certs/localhost/cert.pem",
"privateKey": "/test/certs/localhost/key.pem",
"httpPort": 5002,
"tlsPort": 5001,
"ocspResponderURL": "",
"retryAfter": {
"authz": 3,
"order": 5
},
"externalAccountBindingRequired": true,
"externalAccountMACKeys": {
"kid-1": "zWNDZM6eQGHWpSRTPal5eIUYFTu7EajVIoguysqZ9wG44nMEtx3MUAsUDkMTQ12W",
"kid-2": "b10lLJs8l1GPIzsLP0s6pMt8O0XVGnfTaCeROxQM0BIt2XrJMDHJZBM5NuQmQJQH",
"kid-3": "HjudV5qnbreN-n9WyFSH-t4HXuEx_XFen45zuxY-G1h6fr74V3cUM_dVlwQZBWmc"
},
"certificateValidityPeriod": 157766400
}
}

View file

@ -0,0 +1,27 @@
{
"pebble": {
"listenAddress": "0.0.0.0:14000",
"managementListenAddress": "0.0.0.0:15000",
"certificate": "/test/certs/localhost/cert.pem",
"privateKey": "/test/certs/localhost/key.pem",
"httpPort": 5002,
"tlsPort": 5001,
"ocspResponderURL": "",
"externalAccountBindingRequired": false,
"domainBlocklist": ["blocked-domain.example"],
"retryAfter": {
"authz": 3,
"order": 5
},
"profiles": {
"default": {
"description": "The profile you know and love",
"validityPeriod": 7776000
},
"shortlived": {
"description": "A short-lived cert profile, without actual enforcement",
"validityPeriod": 518400
}
}
}
}

22
.devcontainer/start.sh Executable file
View file

@ -0,0 +1,22 @@
#!/bin/bash
# install zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-autosuggestions ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions
if ! grep -q "zsh-autosuggestions" ~/.zshrc; then
# add zsh-autosuggestions to plugins list
sed -i "/^plugins=(/s/)/ zsh-autosuggestions)/" ~/.zshrc
fi
# init nginx config dir
./.devcontainer/init-nginx.sh
# install app dependencies
echo "Installing app dependencies"
cd app && pnpm install -f
cd ..
# install docs dependencies
echo "Installing docs dependencies"
cd docs && pnpm install -f
cd ..

View file

@ -2,3 +2,6 @@
app/node_modules
.idea
tmp
.devcontainer
.vscode

4
.gitignore vendored
View file

@ -12,7 +12,9 @@ nginx-ui
resources/development/nginx
app/.env
app/.status_hash
casdoor.pub
.idea/deployment.xml
.idea/webServers.xml
*.gen.go
.devcontainer/go-path
.devcontainer/data
.devcontainer/casdoor.pem

14
.idea/nginx-ui.iml generated
View file

@ -1,8 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="Go" enabled="true">
<buildTags>
<option name="customFlags">
<array>
<option value="unembed" />
</array>
</option>
</buildTags>
</component>
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.devcontainer/go-path" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>

48
.vscode/tasks.json vendored Normal file
View file

@ -0,0 +1,48 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Start Backend",
"type": "shell",
"command": "air",
"isBackground": true,
"presentation": {
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Start Frontend",
"type": "shell",
"command": "cd app && pnpm dev",
"isBackground": true,
"presentation": {
"panel": "new"
}
},
{
"label": "Start Documentation",
"type": "shell",
"command": "cd docs && pnpm docs:dev",
"isBackground": true,
"presentation": {
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Start All Services",
"dependsOrder": "parallel",
"dependsOn": [
"Start Backend",
"Start Frontend",
"Start Documentation"
],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
}
]
}

View file

@ -246,7 +246,7 @@ go build -tags=jsoniter -ldflags "$LD_FLAGS -X 'github.com/0xJacky/Nginx-UI/sett
**Instalar and Actualizar**
```shell
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) install
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ install
```
El puerto de escucha predeterminado es `9000` y el puerto de Desafío HTTP predeterminado es `9180`.
Si hay un conflicto de puertos, modifique manualmente `/usr/local/etc/nginx-ui/app.ini`,
@ -255,13 +255,13 @@ luego use `systemctl restart nginx-ui` para recargar el servicio de UI de Nginx.
**Eliminar UI Nginx UI, excepto los archivos de configuración y la base de datos**
```shell
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) remove
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ remove
```
### Uso avanzado
````shell
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) help
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ help
````
## Ejemplo de configuración de proxy reverso de Nginx

View file

@ -300,7 +300,7 @@ go build -tags=jsoniter -ldflags "$LD_FLAGS -X 'github.com/0xJacky/Nginx-UI/sett
**Cài đặt và nâng cấp**
```shell
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) install
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ install
```
Port mặc định để truy cập UI là `9000`, port HTTP Challenge mặc định để xác thực SSL là `9180`.
Nếu có xung đột port, vui lòng sửa đổi trong file `/usr/local/etc/nginx-ui/app.ini`,
@ -309,19 +309,19 @@ hãy nhớ restart nginx-ui bằng lệnh `systemctl restart nginx-ui` mỗi khi
**Gỡ bỏ Nginx UI nhưng giữ lại các tệp cấu hình và cơ sở dữ liệu**
```shell
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) remove
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ remove
```
**Gỡ bỏ Nginx UI đồng thời xoá các tệp cấu hình, cơ sở dữ liệu**
```shell
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) remove --purge
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ remove --purge
```
### Trợ giúp
````shell
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) help
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ help
````
## Ví dụ về cấu hình Nginx Reverse Proxy

View file

@ -240,20 +240,20 @@ go build -tags=jsoniter -ldflags "$LD_FLAGS -X 'github.com/0xJacky/Nginx-UI/sett
**安装或升级**
```shell
bash <(curl -L -s https://mirror.ghproxy.com/https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) install -r https://mirror.ghproxy.com/
bash -c "$(curl -L https://mirror.ghproxy.com/https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ install -r https://mirror.ghproxy.com/
```
一键安装脚本默认设置的监听端口为 `9000`HTTP Challenge 端口默认为 `9180`,如果出现端口冲突请进入 `/usr/local/etc/nginx-ui/app.ini` 修改,并使用 `systemctl restart nginx-ui` 重启 Nginx UI 服务。
**卸载 Nginx UI 但保留配置和数据库文件**
```shell
bash <(curl -L -s https://mirror.ghproxy.com/https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) remove
bash -c "$(curl -L https://mirror.ghproxy.com/https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ remove
```
### 更多用法
````shell
bash <(curl -L -s https://mirror.ghproxy.com/https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) help
bash -c "$(curl -L https://mirror.ghproxy.com/https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ help
````
## Nginx 反向代理配置示例

View file

@ -245,7 +245,7 @@ go build -tags=jsoniter -ldflags "$LD_FLAGS -X 'github.com/0xJacky/Nginx-UI/sett
**安裝或升級**
```shell
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) install
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ install
```
一鍵安裝指令預設的監聽連接埠為 `9000`HTTP Challenge 埠預設為 `9180`,如果出現連接埠衝突請修改 `/usr/local/etc/nginx-ui/app.ini`,並使用 `systemctl restart nginx-ui` 重啟 Nginx UI 守護行程。
@ -253,13 +253,13 @@ bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/instal
**解除安裝 Nginx UI 但保留設定和資料庫檔案**
```shell
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) remove
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ remove
```
### 更多用法
````shell
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) help
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ help
````
## Nginx 反向代理設定範例

View file

@ -102,11 +102,15 @@ URL[https://demo.nginxui.com](https://demo.nginxui.com)
### Internationalization
We proudly offer official support for:
- English
- Simplified Chinese
- Traditional Chinese
We welcome translations into any language.
As non-native English speakers, we strive for accuracy, but we know theres always room for improvement. If you spot any issues, wed love your feedback!
Thanks to our amazing community, additional languages are also available! Explore and contribute to translations on [Weblate](https://weblate.nginxui.com).
### Built With
@ -302,7 +306,7 @@ go build -tags=jsoniter -ldflags "$LD_FLAGS -X 'github.com/0xJacky/Nginx-UI/sett
**Install and Upgrade**
```shell
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) install
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ install
```
The default listening port is `9000`, and the default HTTP Challenge port is `9180`.
If there is a port conflict, please modify `/usr/local/etc/nginx-ui/app.ini` manually,
@ -311,13 +315,13 @@ then use `systemctl restart nginx-ui` to reload the Nginx UI service.
**Remove Nginx UI, except configuration and database files**
```shell
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) remove
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ remove
```
### More Usage
````shell
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) help
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ help
````
## Example of Nginx Reverse Proxy Configuration

View file

@ -4,6 +4,10 @@ import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"io"
"net/http"
"time"
"github.com/0xJacky/Nginx-UI/api"
"github.com/0xJacky/Nginx-UI/internal/analytic"
"github.com/0xJacky/Nginx-UI/internal/cluster"
@ -14,9 +18,6 @@ import (
"github.com/spf13/cast"
"github.com/uozi-tech/cosy"
"gorm.io/gorm"
"io"
"net/http"
"time"
)
func GetEnvironment(c *gin.Context) {
@ -151,23 +152,10 @@ func EditEnvironment(c *gin.Context) {
}
func DeleteEnvironment(c *gin.Context) {
id := cast.ToUint64(c.Param("id"))
envQuery := query.Environment
env, err := envQuery.FirstByID(id)
if err != nil {
api.ErrHandler(c, err)
return
}
err = envQuery.DeleteByID(env.ID)
if err != nil {
api.ErrHandler(c, err)
return
}
go analytic.RestartRetrieveNodesStatus()
c.JSON(http.StatusNoContent, nil)
cosy.Core[model.Environment](c).
ExecutedHook(func(c *cosy.Ctx[model.Environment]) {
go analytic.RestartRetrieveNodesStatus()
}).Destroy()
}
func LoadEnvironmentFromSettings(c *gin.Context) {

View file

@ -15,9 +15,9 @@ func InitPrivateRouter(r *gin.RouterGroup) {
r.GET("upgrade/current", GetCurrentVersion)
r.GET("self_check", SelfCheck)
r.POST("self_check/:name/fix", SelfCheckFix)
r.GET("self_check/websocket", CheckWebSocket)
}
func InitWebSocketRouter(r *gin.RouterGroup) {
r.GET("upgrade/perform", PerformCoreUpgrade)
r.GET("self_check/websocket", CheckWebSocket)
}

View file

@ -1 +1 @@
VITE_PROXY_TARGET=http://127.0.0.1:9001
VITE_PROXY_TARGET=http://127.0.0.1:9000

View file

@ -1,3 +1,5 @@
//go:build !unembed
package app
import (

8
app/app_unembed.go Normal file
View file

@ -0,0 +1,8 @@
//go:build unembed
package app
import "embed"
//go:embed i18n.json src/language/* src/language/*/*
var DistFS embed.FS

View file

@ -2,7 +2,7 @@
"name": "nginx-ui-app-next",
"type": "module",
"version": "2.0.0-rc.1",
"packageManager": "pnpm@9.15.4+sha512.b2dc20e2fc72b3e18848459b37359a32064663e5627a51e4c74b2c29dd8e8e0491483c3abb40789cfd578bf362fb6ba8261b05f0387d76792ed6e23ea3b1b6a0",
"packageManager": "pnpm@10.2.0+sha512.0d27364e0139c6aadeed65ada153135e0ca96c8da42123bd50047f961339dc7a758fc2e944b428f52be570d1bd3372455c1c65fa2e7aa0bfbf931190f9552001",
"scripts": {
"dev": "vite --host",
"typecheck": "vue-tsc --noEmit",
@ -52,14 +52,14 @@
"vuedraggable": "^4.1.0"
},
"devDependencies": {
"@antfu/eslint-config": "^4.1.0",
"@antfu/eslint-config": "^4.1.1",
"@iconify-json/fa": "1.2.1",
"@iconify-json/tabler": "^1.2.14",
"@iconify-json/tabler": "^1.2.15",
"@iconify/tools": "^4.1.1",
"@iconify/types": "^2.0.0",
"@iconify/utils": "^2.2.1",
"@iconify/vue": "^4.3.0",
"@types/lodash": "^4.17.14",
"@types/lodash": "^4.17.15",
"@types/nprogress": "^0.2.3",
"@types/sortablejs": "^1.15.8",
"@vitejs/plugin-vue": "^5.2.1",
@ -68,7 +68,7 @@
"@vue/tsconfig": "^0.7.0",
"ace-builds": "^1.37.5",
"autoprefixer": "^10.4.20",
"eslint": "9.18.0",
"eslint": "9.19.0",
"eslint-plugin-sonarjs": "^3.0.1",
"less": "^4.2.2",
"postcss": "^8.5.1",

462
app/pnpm-lock.yaml generated
View file

@ -121,14 +121,14 @@ importers:
version: 4.1.0(vue@3.5.13(typescript@5.7.3))
devDependencies:
'@antfu/eslint-config':
specifier: ^4.1.0
version: 4.1.0(@typescript-eslint/utils@8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3))(@vue/compiler-sfc@3.5.13)(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)
specifier: ^4.1.1
version: 4.1.1(@typescript-eslint/utils@8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3))(@vue/compiler-sfc@3.5.13)(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)
'@iconify-json/fa':
specifier: 1.2.1
version: 1.2.1
'@iconify-json/tabler':
specifier: ^1.2.14
version: 1.2.14
specifier: ^1.2.15
version: 1.2.15
'@iconify/tools':
specifier: ^4.1.1
version: 4.1.1
@ -142,8 +142,8 @@ importers:
specifier: ^4.3.0
version: 4.3.0(vue@3.5.13(typescript@5.7.3))
'@types/lodash':
specifier: ^4.17.14
version: 4.17.14
specifier: ^4.17.15
version: 4.17.15
'@types/nprogress':
specifier: ^0.2.3
version: 0.2.3
@ -169,11 +169,11 @@ importers:
specifier: ^10.4.20
version: 10.4.20(postcss@8.5.1)
eslint:
specifier: 9.18.0
version: 9.18.0(jiti@2.4.1)
specifier: 9.19.0
version: 9.19.0(jiti@2.4.1)
eslint-plugin-sonarjs:
specifier: ^3.0.1
version: 3.0.1(eslint@9.18.0(jiti@2.4.1))
version: 3.0.1(eslint@9.19.0(jiti@2.4.1))
less:
specifier: ^4.2.2
version: 4.2.2
@ -222,8 +222,8 @@ packages:
peerDependencies:
vue: '>=3.0.3'
'@antfu/eslint-config@4.1.0':
resolution: {integrity: sha512-2yainF3mBykqzsxXbHYGuLwm60sRRzQqJdLJd2IfESIGkkIkQfUI3IEGTANGpdWSmiC9jhICP7Y8yY+TSKGUQg==}
'@antfu/eslint-config@4.1.1':
resolution: {integrity: sha512-5UVRu8uC6Q9e+o49ppafvIfOT3geqo74bZNAZ1Rvx10OF8gkUh7gT6b5yEJkUeej3WHRyVw3kTTgK52To1E+VQ==}
hasBin: true
peerDependencies:
'@eslint-react/eslint-plugin': ^1.19.0
@ -1197,8 +1197,8 @@ packages:
resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
'@eslint/compat@1.2.4':
resolution: {integrity: sha512-S8ZdQj/N69YAtuqFt7653jwcvuUj131+6qGLUyDqfDg1OIoBQ66OCuXC473YQfO2AaxITTutiRQiDwoo7ZLYyg==}
'@eslint/compat@1.2.6':
resolution: {integrity: sha512-k7HNCqApoDHM6XzT30zGoETj+D+uUcZUb+IVAJmar3u6bvHf7hhHJcWx09QHj4/a2qrKZMWU0E16tvkiAdv06Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^9.10.0
@ -1218,8 +1218,8 @@ packages:
resolution: {integrity: sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/js@9.18.0':
resolution: {integrity: sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==}
'@eslint/js@9.19.0':
resolution: {integrity: sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/markdown@6.2.2':
@ -1260,8 +1260,8 @@ packages:
'@iconify-json/fa@1.2.1':
resolution: {integrity: sha512-aY2+tQNWq5ch+ShtAz3KKbNrFfwf4BPrXvyN7S4/lcf6Wms+kIxsd7C7KortzHZhoBnbhVN+qo+YUWLW7rLs9Q==}
'@iconify-json/tabler@1.2.14':
resolution: {integrity: sha512-X5Li79KW5KilHIaNVFKMuPr0WOA4B/Y/EqkrrZiEihs3Wcq/eIDMDDqGBkmei/8naYyfpkj0LWH7osr+vJYFEA==}
'@iconify-json/tabler@1.2.15':
resolution: {integrity: sha512-EMEOt1PubLxcbwHMO9XmHT601A/2fCNd7fK50p5Qh42xvVxCvO3YhhGuGMAk6t6VkdSZYLQ14Y2bYPcom1aFeQ==}
'@iconify/tools@4.1.1':
resolution: {integrity: sha512-Hybu/HGhv6T8nLQhiG9rKx+ekF7NNpPOEQAy7JRSKht3s3dcFSsPccYzk24Znc9MTxrR6Gak3cg6CPP5dyvS2Q==}
@ -1447,8 +1447,8 @@ packages:
resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==}
engines: {node: '>=18'}
'@stylistic/eslint-plugin@3.0.0':
resolution: {integrity: sha512-9GJI6iBtGjOqSsyCKUvE6Vn7qDT52hbQaoq/SwxH6A1bciymZfvBfHIIrD3E7Koi2sjzOa/MNQ2XOguHtVJOyw==}
'@stylistic/eslint-plugin@3.0.1':
resolution: {integrity: sha512-rQ3tcT5N2cynofJfbjUsnL4seoewTaOVBLyUEwtNldo7iNMPo3h/GUQk+Cl3iHEWwRxjq2wuH6q0FufQrbVL1A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: '>=8.40.0'
@ -1503,8 +1503,8 @@ packages:
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
'@types/lodash@4.17.14':
resolution: {integrity: sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A==}
'@types/lodash@4.17.15':
resolution: {integrity: sha512-w/P33JFeySuhN6JLkysYUK2gEmy9kHHFN7E8ro0tkfmlDOgxBDzWEZ/J8cWA+fHqFevpswDTFZnDx+R9lbL6xw==}
'@types/mdast@4.0.4':
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
@ -1545,52 +1545,43 @@ packages:
'@types/yauzl@2.10.3':
resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
'@typescript-eslint/eslint-plugin@8.21.0':
resolution: {integrity: sha512-eTH+UOR4I7WbdQnG4Z48ebIA6Bgi7WO8HvFEneeYBxG8qCOYgTOFPSg6ek9ITIDvGjDQzWHcoWHCDO2biByNzA==}
'@typescript-eslint/eslint-plugin@8.23.0':
resolution: {integrity: sha512-vBz65tJgRrA1Q5gWlRfvoH+w943dq9K1p1yDBY2pc+a1nbBLZp7fB9+Hk8DaALUbzjqlMfgaqlVPT1REJdkt/w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
'@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.8.0'
'@typescript-eslint/parser@8.21.0':
resolution: {integrity: sha512-Wy+/sdEH9kI3w9civgACwabHbKl+qIOu0uFZ9IMKzX3Jpv9og0ZBJrZExGrPpFAY7rWsXuxs5e7CPPP17A4eYA==}
'@typescript-eslint/parser@8.23.0':
resolution: {integrity: sha512-h2lUByouOXFAlMec2mILeELUbME5SZRN/7R9Cw2RD2lRQQY08MWMM+PmVVKKJNK1aIwqTo9t/0CvOxwPbRIE2Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.8.0'
'@typescript-eslint/scope-manager@8.13.0':
resolution: {integrity: sha512-XsGWww0odcUT0gJoBZ1DeulY1+jkaHUciUq4jKNv4cpInbvvrtDoyBH9rE/n2V29wQJPk8iCH1wipra9BhmiMA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/scope-manager@8.21.0':
resolution: {integrity: sha512-G3IBKz0/0IPfdeGRMbp+4rbjfSSdnGkXsM/pFZA8zM9t9klXDnB/YnKOBQ0GoPmoROa4bCq2NeHgJa5ydsQ4mA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/type-utils@8.21.0':
resolution: {integrity: sha512-95OsL6J2BtzoBxHicoXHxgk3z+9P3BEcQTpBKriqiYzLKnM2DeSqs+sndMKdamU8FosiadQFT3D+BSL9EKnAJQ==}
'@typescript-eslint/scope-manager@8.23.0':
resolution: {integrity: sha512-OGqo7+dXHqI7Hfm+WqkZjKjsiRtFUQHPdGMXzk5mYXhJUedO7e/Y7i8AK3MyLMgZR93TX4bIzYrfyVjLC+0VSw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/type-utils@8.23.0':
resolution: {integrity: sha512-iIuLdYpQWZKbiH+RkCGc6iu+VwscP5rCtQ1lyQ7TYuKLrcZoeJVpcLiG8DliXVkUxirW/PWlmS+d6yD51L9jvA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.8.0'
'@typescript-eslint/types@8.13.0':
resolution: {integrity: sha512-4cyFErJetFLckcThRUFdReWJjVsPCqyBlJTi6IDEpc1GWCIIZRFxVppjWLIMcQhNGhdWJJRYFHpHoDWvMlDzng==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/types@8.21.0':
resolution: {integrity: sha512-PAL6LUuQwotLW2a8VsySDBwYMm129vFm4tMVlylzdoTybTHaAi0oBp7Ac6LhSrHHOdLM3efH+nAR6hAWoMF89A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@8.13.0':
resolution: {integrity: sha512-v7SCIGmVsRK2Cy/LTLGN22uea6SaUIlpBcO/gnMGT/7zPtxp90bphcGf4fyrCQl3ZtiBKqVTG32hb668oIYy1g==}
'@typescript-eslint/types@8.23.0':
resolution: {integrity: sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
'@typescript-eslint/typescript-estree@8.21.0':
resolution: {integrity: sha512-x+aeKh/AjAArSauz0GiQZsjT8ciadNMHdkUSwBB9Z6PrKc/4knM4g3UfHml6oDJmKC88a6//cdxnO/+P2LkMcg==}
@ -1598,11 +1589,11 @@ packages:
peerDependencies:
typescript: '>=4.8.4 <5.8.0'
'@typescript-eslint/utils@8.13.0':
resolution: {integrity: sha512-A1EeYOND6Uv250nybnLZapeXpYMl8tkzYUxqmoKAWnI4sei3ihf2XdZVd+vVOmHGcp3t+P7yRrNsyyiXTvShFQ==}
'@typescript-eslint/typescript-estree@8.23.0':
resolution: {integrity: sha512-LcqzfipsB8RTvH8FX24W4UUFk1bl+0yTOf9ZA08XngFwMg4Kj8A+9hwz8Cr/ZS4KwHrmo9PJiLZkOt49vPnuvQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.8.0'
'@typescript-eslint/utils@8.21.0':
resolution: {integrity: sha512-xcXBfcq0Kaxgj7dwejMbFyq7IOHgpNMtVuDveK7w3ZGwG9owKzhALVwKpTF2yrZmEwl9SWdetf3fxNzJQaVuxw==}
@ -1611,14 +1602,21 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.8.0'
'@typescript-eslint/visitor-keys@8.13.0':
resolution: {integrity: sha512-7N/+lztJqH4Mrf0lb10R/CbI1EaAMMGyF5y0oJvFoAhafwgiRA7TXyd8TFn8FC8k5y2dTsYogg238qavRGNnlw==}
'@typescript-eslint/utils@8.23.0':
resolution: {integrity: sha512-uB/+PSo6Exu02b5ZEiVtmY6RVYO7YU5xqgzTIVZwTHvvK3HsL8tZZHFaTLFtRG3CsV4A5mhOv+NZx5BlhXPyIA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.8.0'
'@typescript-eslint/visitor-keys@8.21.0':
resolution: {integrity: sha512-BkLMNpdV6prozk8LlyK/SOoWLmUFi+ZD+pcqti9ILCbVvHGk1ui1g4jJOc2WDLaeExz2qWwojxlPce5PljcT3w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/visitor-keys@8.23.0':
resolution: {integrity: sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@unocss/astro@65.4.3':
resolution: {integrity: sha512-yhPKH4CT2CFjvKR8lL6oS/7jarMWp4iSnYcNlTlZLmvTIS3dGxyhAsVy/xkdzdJ6sM+6FS0hUuQNv+NYvArRNg==}
peerDependencies:
@ -2467,13 +2465,13 @@ packages:
peerDependencies:
eslint: '>=6.0.0'
eslint-config-flat-gitignore@1.0.0:
resolution: {integrity: sha512-EWpSLrAP80IdcYK5sIhq/qAY0pmUdBnbzqzpE3QAn6H6wLBN26cMRoMNU9Di8upTzUSL6TXeYRxWhTYuz8+UQA==}
eslint-config-flat-gitignore@2.0.0:
resolution: {integrity: sha512-9iH+DZO94uxsw5iFjzqa9GfahA5oK3nA1GoJK/6u8evAtooYJMwuSWiLcGDfrdLoqdQ5/kqFJKKuMY/+SAasvg==}
peerDependencies:
eslint: ^9.5.0
eslint-flat-config-utils@2.0.0:
resolution: {integrity: sha512-AbpYwI9FBmjF6BQ8UcaDCrM750DWEB6UJzEjQEg+iWFP6UX9rGsUGJlMf7sWbW3dOA0klUEwmWGZa5FoynXU/w==}
eslint-flat-config-utils@2.0.1:
resolution: {integrity: sha512-brf0eAgQ6JlKj3bKfOTuuI7VcCZvi8ZCD1MMTVoEvS/d38j8cByZViLFALH/36+eqB17ukmfmKq3bWzGvizejA==}
eslint-import-resolver-node@0.3.9:
resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
@ -2618,8 +2616,8 @@ packages:
resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
eslint@9.18.0:
resolution: {integrity: sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==}
eslint@9.19.0:
resolution: {integrity: sha512-ug92j0LepKlbbEv6hD911THhoRHmbdXt2gX+VDABAW/Ir7D3nqKdv5Pf5vtlyY6HQMTEP2skXY43ueqTCWssEA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
hasBin: true
peerDependencies:
@ -2710,10 +2708,6 @@ packages:
resolution: {integrity: sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==}
engines: {node: '>=4.0.0'}
find-up-simple@1.0.0:
resolution: {integrity: sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==}
engines: {node: '>=18'}
find-up@4.1.0:
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
engines: {node: '>=8'}
@ -4124,18 +4118,18 @@ packages:
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
engines: {node: '>=6'}
ts-api-utils@1.4.3:
resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==}
engines: {node: '>=16'}
peerDependencies:
typescript: '>=4.2.0'
ts-api-utils@2.0.0:
resolution: {integrity: sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==}
engines: {node: '>=18.12'}
peerDependencies:
typescript: '>=4.8.4'
ts-api-utils@2.0.1:
resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==}
engines: {node: '>=18.12'}
peerDependencies:
typescript: '>=4.8.4'
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
@ -4564,42 +4558,42 @@ snapshots:
'@ant-design/icons-svg': 4.4.2
vue: 3.5.13(typescript@5.7.3)
'@antfu/eslint-config@4.1.0(@typescript-eslint/utils@8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3))(@vue/compiler-sfc@3.5.13)(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)':
'@antfu/eslint-config@4.1.1(@typescript-eslint/utils@8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3))(@vue/compiler-sfc@3.5.13)(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)':
dependencies:
'@antfu/install-pkg': 1.0.0
'@clack/prompts': 0.9.1
'@eslint-community/eslint-plugin-eslint-comments': 4.4.1(eslint@9.18.0(jiti@2.4.1))
'@eslint-community/eslint-plugin-eslint-comments': 4.4.1(eslint@9.19.0(jiti@2.4.1))
'@eslint/markdown': 6.2.2
'@stylistic/eslint-plugin': 3.0.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)
'@typescript-eslint/eslint-plugin': 8.21.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)
'@typescript-eslint/parser': 8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)
'@vitest/eslint-plugin': 1.1.25(@typescript-eslint/utils@8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)
eslint: 9.18.0(jiti@2.4.1)
eslint-config-flat-gitignore: 1.0.0(eslint@9.18.0(jiti@2.4.1))
eslint-flat-config-utils: 2.0.0
eslint-merge-processors: 1.0.0(eslint@9.18.0(jiti@2.4.1))
eslint-plugin-antfu: 3.0.0(eslint@9.18.0(jiti@2.4.1))
eslint-plugin-command: 3.0.0(eslint@9.18.0(jiti@2.4.1))
eslint-plugin-import-x: 4.6.1(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)
eslint-plugin-jsdoc: 50.6.3(eslint@9.18.0(jiti@2.4.1))
eslint-plugin-jsonc: 2.19.1(eslint@9.18.0(jiti@2.4.1))
eslint-plugin-n: 17.15.1(eslint@9.18.0(jiti@2.4.1))
'@stylistic/eslint-plugin': 3.0.1(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)
'@typescript-eslint/eslint-plugin': 8.23.0(@typescript-eslint/parser@8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)
'@typescript-eslint/parser': 8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)
'@vitest/eslint-plugin': 1.1.25(@typescript-eslint/utils@8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)
eslint: 9.19.0(jiti@2.4.1)
eslint-config-flat-gitignore: 2.0.0(eslint@9.19.0(jiti@2.4.1))
eslint-flat-config-utils: 2.0.1
eslint-merge-processors: 1.0.0(eslint@9.19.0(jiti@2.4.1))
eslint-plugin-antfu: 3.0.0(eslint@9.19.0(jiti@2.4.1))
eslint-plugin-command: 3.0.0(eslint@9.19.0(jiti@2.4.1))
eslint-plugin-import-x: 4.6.1(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)
eslint-plugin-jsdoc: 50.6.3(eslint@9.19.0(jiti@2.4.1))
eslint-plugin-jsonc: 2.19.1(eslint@9.19.0(jiti@2.4.1))
eslint-plugin-n: 17.15.1(eslint@9.19.0(jiti@2.4.1))
eslint-plugin-no-only-tests: 3.3.0
eslint-plugin-perfectionist: 4.7.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)
eslint-plugin-regexp: 2.7.0(eslint@9.18.0(jiti@2.4.1))
eslint-plugin-toml: 0.12.0(eslint@9.18.0(jiti@2.4.1))
eslint-plugin-unicorn: 56.0.1(eslint@9.18.0(jiti@2.4.1))
eslint-plugin-unused-imports: 4.1.4(@typescript-eslint/eslint-plugin@8.21.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.1))
eslint-plugin-vue: 9.32.0(eslint@9.18.0(jiti@2.4.1))
eslint-plugin-yml: 1.16.0(eslint@9.18.0(jiti@2.4.1))
eslint-processor-vue-blocks: 1.0.0(@vue/compiler-sfc@3.5.13)(eslint@9.18.0(jiti@2.4.1))
eslint-plugin-perfectionist: 4.7.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)
eslint-plugin-regexp: 2.7.0(eslint@9.19.0(jiti@2.4.1))
eslint-plugin-toml: 0.12.0(eslint@9.19.0(jiti@2.4.1))
eslint-plugin-unicorn: 56.0.1(eslint@9.19.0(jiti@2.4.1))
eslint-plugin-unused-imports: 4.1.4(@typescript-eslint/eslint-plugin@8.23.0(@typescript-eslint/parser@8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.1))
eslint-plugin-vue: 9.32.0(eslint@9.19.0(jiti@2.4.1))
eslint-plugin-yml: 1.16.0(eslint@9.19.0(jiti@2.4.1))
eslint-processor-vue-blocks: 1.0.0(@vue/compiler-sfc@3.5.13)(eslint@9.19.0(jiti@2.4.1))
globals: 15.14.0
jsonc-eslint-parser: 2.4.0
local-pkg: 1.0.0
parse-gitignore: 2.0.0
picocolors: 1.1.1
toml-eslint-parser: 0.10.0
vue-eslint-parser: 9.4.3(eslint@9.18.0(jiti@2.4.1))
vue-eslint-parser: 9.4.3(eslint@9.19.0(jiti@2.4.1))
yaml-eslint-parser: 1.2.3
yargs: 17.7.2
transitivePeerDependencies:
@ -4652,11 +4646,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@babel/eslint-parser@7.25.9(@babel/core@7.26.0)(eslint@9.18.0(jiti@2.4.1))':
'@babel/eslint-parser@7.25.9(@babel/core@7.26.0)(eslint@9.19.0(jiti@2.4.1))':
dependencies:
'@babel/core': 7.26.0
'@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
eslint-visitor-keys: 2.1.0
semver: 6.3.1
@ -5555,22 +5549,22 @@ snapshots:
'@esbuild/win32-x64@0.24.2':
optional: true
'@eslint-community/eslint-plugin-eslint-comments@4.4.1(eslint@9.18.0(jiti@2.4.1))':
'@eslint-community/eslint-plugin-eslint-comments@4.4.1(eslint@9.19.0(jiti@2.4.1))':
dependencies:
escape-string-regexp: 4.0.0
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
ignore: 5.3.2
'@eslint-community/eslint-utils@4.4.1(eslint@9.18.0(jiti@2.4.1))':
'@eslint-community/eslint-utils@4.4.1(eslint@9.19.0(jiti@2.4.1))':
dependencies:
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.12.1': {}
'@eslint/compat@1.2.4(eslint@9.18.0(jiti@2.4.1))':
'@eslint/compat@1.2.6(eslint@9.19.0(jiti@2.4.1))':
optionalDependencies:
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
'@eslint/config-array@0.19.1':
dependencies:
@ -5598,7 +5592,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@eslint/js@9.18.0': {}
'@eslint/js@9.19.0': {}
'@eslint/markdown@6.2.2':
dependencies:
@ -5636,7 +5630,7 @@ snapshots:
dependencies:
'@iconify/types': 2.0.0
'@iconify-json/tabler@1.2.14':
'@iconify-json/tabler@1.2.15':
dependencies:
'@iconify/types': 2.0.0
@ -5847,10 +5841,10 @@ snapshots:
'@sindresorhus/merge-streams@2.3.0': {}
'@stylistic/eslint-plugin@3.0.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)':
'@stylistic/eslint-plugin@3.0.1(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)':
dependencies:
'@typescript-eslint/utils': 8.13.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)
eslint: 9.18.0(jiti@2.4.1)
'@typescript-eslint/utils': 8.21.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)
eslint: 9.19.0(jiti@2.4.1)
eslint-visitor-keys: 4.2.0
espree: 10.3.0
estraverse: 5.3.0
@ -5902,7 +5896,7 @@ snapshots:
'@types/json-schema@7.0.15': {}
'@types/lodash@4.17.14': {}
'@types/lodash@4.17.15': {}
'@types/mdast@4.0.4':
dependencies:
@ -5941,74 +5935,59 @@ snapshots:
'@types/node': 22.10.2
optional: true
'@typescript-eslint/eslint-plugin@8.21.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)':
'@typescript-eslint/eslint-plugin@8.23.0(@typescript-eslint/parser@8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)':
dependencies:
'@eslint-community/regexpp': 4.12.1
'@typescript-eslint/parser': 8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)
'@typescript-eslint/scope-manager': 8.21.0
'@typescript-eslint/type-utils': 8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)
'@typescript-eslint/utils': 8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)
'@typescript-eslint/visitor-keys': 8.21.0
eslint: 9.18.0(jiti@2.4.1)
'@typescript-eslint/parser': 8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)
'@typescript-eslint/scope-manager': 8.23.0
'@typescript-eslint/type-utils': 8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)
'@typescript-eslint/utils': 8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)
'@typescript-eslint/visitor-keys': 8.23.0
eslint: 9.19.0(jiti@2.4.1)
graphemer: 1.4.0
ignore: 5.3.2
natural-compare: 1.4.0
ts-api-utils: 2.0.0(typescript@5.7.3)
ts-api-utils: 2.0.1(typescript@5.7.3)
typescript: 5.7.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)':
'@typescript-eslint/parser@8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.21.0
'@typescript-eslint/types': 8.21.0
'@typescript-eslint/typescript-estree': 8.21.0(typescript@5.7.3)
'@typescript-eslint/visitor-keys': 8.21.0
'@typescript-eslint/scope-manager': 8.23.0
'@typescript-eslint/types': 8.23.0
'@typescript-eslint/typescript-estree': 8.23.0(typescript@5.7.3)
'@typescript-eslint/visitor-keys': 8.23.0
debug: 4.4.0
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
typescript: 5.7.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/scope-manager@8.13.0':
dependencies:
'@typescript-eslint/types': 8.13.0
'@typescript-eslint/visitor-keys': 8.13.0
'@typescript-eslint/scope-manager@8.21.0':
dependencies:
'@typescript-eslint/types': 8.21.0
'@typescript-eslint/visitor-keys': 8.21.0
'@typescript-eslint/type-utils@8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)':
'@typescript-eslint/scope-manager@8.23.0':
dependencies:
'@typescript-eslint/typescript-estree': 8.21.0(typescript@5.7.3)
'@typescript-eslint/utils': 8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)
'@typescript-eslint/types': 8.23.0
'@typescript-eslint/visitor-keys': 8.23.0
'@typescript-eslint/type-utils@8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)':
dependencies:
'@typescript-eslint/typescript-estree': 8.23.0(typescript@5.7.3)
'@typescript-eslint/utils': 8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)
debug: 4.4.0
eslint: 9.18.0(jiti@2.4.1)
ts-api-utils: 2.0.0(typescript@5.7.3)
eslint: 9.19.0(jiti@2.4.1)
ts-api-utils: 2.0.1(typescript@5.7.3)
typescript: 5.7.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/types@8.13.0': {}
'@typescript-eslint/types@8.21.0': {}
'@typescript-eslint/typescript-estree@8.13.0(typescript@5.7.3)':
dependencies:
'@typescript-eslint/types': 8.13.0
'@typescript-eslint/visitor-keys': 8.13.0
debug: 4.4.0
fast-glob: 3.3.3
is-glob: 4.0.3
minimatch: 9.0.5
semver: 7.6.3
ts-api-utils: 1.4.3(typescript@5.7.3)
optionalDependencies:
typescript: 5.7.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/types@8.23.0': {}
'@typescript-eslint/typescript-estree@8.21.0(typescript@5.7.3)':
dependencies:
@ -6024,38 +6003,52 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.13.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)':
'@typescript-eslint/typescript-estree@8.23.0(typescript@5.7.3)':
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.1))
'@typescript-eslint/scope-manager': 8.13.0
'@typescript-eslint/types': 8.13.0
'@typescript-eslint/typescript-estree': 8.13.0(typescript@5.7.3)
eslint: 9.18.0(jiti@2.4.1)
transitivePeerDependencies:
- supports-color
- typescript
'@typescript-eslint/utils@8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)':
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.1))
'@typescript-eslint/scope-manager': 8.21.0
'@typescript-eslint/types': 8.21.0
'@typescript-eslint/typescript-estree': 8.21.0(typescript@5.7.3)
eslint: 9.18.0(jiti@2.4.1)
'@typescript-eslint/types': 8.23.0
'@typescript-eslint/visitor-keys': 8.23.0
debug: 4.4.0
fast-glob: 3.3.3
is-glob: 4.0.3
minimatch: 9.0.5
semver: 7.6.3
ts-api-utils: 2.0.1(typescript@5.7.3)
typescript: 5.7.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/visitor-keys@8.13.0':
'@typescript-eslint/utils@8.21.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)':
dependencies:
'@typescript-eslint/types': 8.13.0
eslint-visitor-keys: 3.4.3
'@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.1))
'@typescript-eslint/scope-manager': 8.21.0
'@typescript-eslint/types': 8.21.0
'@typescript-eslint/typescript-estree': 8.21.0(typescript@5.7.3)
eslint: 9.19.0(jiti@2.4.1)
typescript: 5.7.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)':
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.1))
'@typescript-eslint/scope-manager': 8.23.0
'@typescript-eslint/types': 8.23.0
'@typescript-eslint/typescript-estree': 8.23.0(typescript@5.7.3)
eslint: 9.19.0(jiti@2.4.1)
typescript: 5.7.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/visitor-keys@8.21.0':
dependencies:
'@typescript-eslint/types': 8.21.0
eslint-visitor-keys: 4.2.0
'@typescript-eslint/visitor-keys@8.23.0':
dependencies:
'@typescript-eslint/types': 8.23.0
eslint-visitor-keys: 4.2.0
'@unocss/astro@65.4.3(rollup@4.28.1)(vite@6.0.11(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.2)(tsx@4.19.2)(yaml@2.6.1))(vue@3.5.13(typescript@5.7.3))':
dependencies:
'@unocss/core': 65.4.3
@ -6223,10 +6216,10 @@ snapshots:
vite: 6.0.11(@types/node@22.10.2)(jiti@2.4.1)(less@4.2.2)(tsx@4.19.2)(yaml@2.6.1)
vue: 3.5.13(typescript@5.7.3)
'@vitest/eslint-plugin@1.1.25(@typescript-eslint/utils@8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)':
'@vitest/eslint-plugin@1.1.25(@typescript-eslint/utils@8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)':
dependencies:
'@typescript-eslint/utils': 8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)
eslint: 9.18.0(jiti@2.4.1)
'@typescript-eslint/utils': 8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)
eslint: 9.19.0(jiti@2.4.1)
optionalDependencies:
typescript: 5.7.3
@ -7114,23 +7107,22 @@ snapshots:
escape-string-regexp@5.0.0: {}
eslint-compat-utils@0.5.1(eslint@9.18.0(jiti@2.4.1)):
eslint-compat-utils@0.5.1(eslint@9.19.0(jiti@2.4.1)):
dependencies:
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
semver: 7.6.3
eslint-compat-utils@0.6.4(eslint@9.18.0(jiti@2.4.1)):
eslint-compat-utils@0.6.4(eslint@9.19.0(jiti@2.4.1)):
dependencies:
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
semver: 7.6.3
eslint-config-flat-gitignore@1.0.0(eslint@9.18.0(jiti@2.4.1)):
eslint-config-flat-gitignore@2.0.0(eslint@9.19.0(jiti@2.4.1)):
dependencies:
'@eslint/compat': 1.2.4(eslint@9.18.0(jiti@2.4.1))
eslint: 9.18.0(jiti@2.4.1)
find-up-simple: 1.0.0
'@eslint/compat': 1.2.6(eslint@9.19.0(jiti@2.4.1))
eslint: 9.19.0(jiti@2.4.1)
eslint-flat-config-utils@2.0.0:
eslint-flat-config-utils@2.0.1:
dependencies:
pathe: 2.0.2
@ -7142,41 +7134,41 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-json-compat-utils@0.2.1(eslint@9.18.0(jiti@2.4.1))(jsonc-eslint-parser@2.4.0):
eslint-json-compat-utils@0.2.1(eslint@9.19.0(jiti@2.4.1))(jsonc-eslint-parser@2.4.0):
dependencies:
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
esquery: 1.6.0
jsonc-eslint-parser: 2.4.0
eslint-merge-processors@1.0.0(eslint@9.18.0(jiti@2.4.1)):
eslint-merge-processors@1.0.0(eslint@9.19.0(jiti@2.4.1)):
dependencies:
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
eslint-plugin-antfu@3.0.0(eslint@9.18.0(jiti@2.4.1)):
eslint-plugin-antfu@3.0.0(eslint@9.19.0(jiti@2.4.1)):
dependencies:
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
eslint-plugin-command@3.0.0(eslint@9.18.0(jiti@2.4.1)):
eslint-plugin-command@3.0.0(eslint@9.19.0(jiti@2.4.1)):
dependencies:
'@es-joy/jsdoccomment': 0.50.0
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
eslint-plugin-es-x@7.8.0(eslint@9.18.0(jiti@2.4.1)):
eslint-plugin-es-x@7.8.0(eslint@9.19.0(jiti@2.4.1)):
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.1))
'@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.1))
'@eslint-community/regexpp': 4.12.1
eslint: 9.18.0(jiti@2.4.1)
eslint-compat-utils: 0.5.1(eslint@9.18.0(jiti@2.4.1))
eslint: 9.19.0(jiti@2.4.1)
eslint-compat-utils: 0.5.1(eslint@9.19.0(jiti@2.4.1))
eslint-plugin-import-x@4.6.1(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3):
eslint-plugin-import-x@4.6.1(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3):
dependencies:
'@types/doctrine': 0.0.9
'@typescript-eslint/scope-manager': 8.21.0
'@typescript-eslint/utils': 8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)
'@typescript-eslint/utils': 8.21.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)
debug: 4.4.0
doctrine: 3.0.0
enhanced-resolve: 5.17.1
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
eslint-import-resolver-node: 0.3.9
get-tsconfig: 4.8.1
is-glob: 4.0.3
@ -7188,14 +7180,14 @@ snapshots:
- supports-color
- typescript
eslint-plugin-jsdoc@50.6.3(eslint@9.18.0(jiti@2.4.1)):
eslint-plugin-jsdoc@50.6.3(eslint@9.19.0(jiti@2.4.1)):
dependencies:
'@es-joy/jsdoccomment': 0.49.0
are-docs-informative: 0.0.2
comment-parser: 1.4.1
debug: 4.4.0
escape-string-regexp: 4.0.0
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
espree: 10.3.0
esquery: 1.6.0
parse-imports: 2.2.1
@ -7205,12 +7197,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-plugin-jsonc@2.19.1(eslint@9.18.0(jiti@2.4.1)):
eslint-plugin-jsonc@2.19.1(eslint@9.19.0(jiti@2.4.1)):
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.1))
eslint: 9.18.0(jiti@2.4.1)
eslint-compat-utils: 0.6.4(eslint@9.18.0(jiti@2.4.1))
eslint-json-compat-utils: 0.2.1(eslint@9.18.0(jiti@2.4.1))(jsonc-eslint-parser@2.4.0)
'@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.1))
eslint: 9.19.0(jiti@2.4.1)
eslint-compat-utils: 0.6.4(eslint@9.19.0(jiti@2.4.1))
eslint-json-compat-utils: 0.2.1(eslint@9.19.0(jiti@2.4.1))(jsonc-eslint-parser@2.4.0)
espree: 9.6.1
graphemer: 1.4.0
jsonc-eslint-parser: 2.4.0
@ -7219,12 +7211,12 @@ snapshots:
transitivePeerDependencies:
- '@eslint/json'
eslint-plugin-n@17.15.1(eslint@9.18.0(jiti@2.4.1)):
eslint-plugin-n@17.15.1(eslint@9.19.0(jiti@2.4.1)):
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.1))
'@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.1))
enhanced-resolve: 5.17.1
eslint: 9.18.0(jiti@2.4.1)
eslint-plugin-es-x: 7.8.0(eslint@9.18.0(jiti@2.4.1))
eslint: 9.19.0(jiti@2.4.1)
eslint-plugin-es-x: 7.8.0(eslint@9.19.0(jiti@2.4.1))
get-tsconfig: 4.8.1
globals: 15.14.0
ignore: 5.3.2
@ -7233,31 +7225,31 @@ snapshots:
eslint-plugin-no-only-tests@3.3.0: {}
eslint-plugin-perfectionist@4.7.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3):
eslint-plugin-perfectionist@4.7.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3):
dependencies:
'@typescript-eslint/types': 8.21.0
'@typescript-eslint/utils': 8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)
eslint: 9.18.0(jiti@2.4.1)
'@typescript-eslint/utils': 8.21.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)
eslint: 9.19.0(jiti@2.4.1)
natural-orderby: 5.0.0
transitivePeerDependencies:
- supports-color
- typescript
eslint-plugin-regexp@2.7.0(eslint@9.18.0(jiti@2.4.1)):
eslint-plugin-regexp@2.7.0(eslint@9.19.0(jiti@2.4.1)):
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.1))
'@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.1))
'@eslint-community/regexpp': 4.12.1
comment-parser: 1.4.1
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
jsdoc-type-pratt-parser: 4.1.0
refa: 0.12.1
regexp-ast-analysis: 0.7.1
scslre: 0.3.0
eslint-plugin-sonarjs@3.0.1(eslint@9.18.0(jiti@2.4.1)):
eslint-plugin-sonarjs@3.0.1(eslint@9.19.0(jiti@2.4.1)):
dependencies:
'@babel/core': 7.26.0
'@babel/eslint-parser': 7.25.9(@babel/core@7.26.0)(eslint@9.18.0(jiti@2.4.1))
'@babel/eslint-parser': 7.25.9(@babel/core@7.26.0)(eslint@9.19.0(jiti@2.4.1))
'@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.0)
'@babel/preset-env': 7.26.0(@babel/core@7.26.0)
'@babel/preset-flow': 7.25.9(@babel/core@7.26.0)
@ -7265,7 +7257,7 @@ snapshots:
'@eslint-community/regexpp': 4.12.1
builtin-modules: 3.3.0
bytes: 3.1.2
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
functional-red-black-tree: 1.0.1
jsx-ast-utils: 3.3.5
minimatch: 9.0.5
@ -7275,24 +7267,24 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-plugin-toml@0.12.0(eslint@9.18.0(jiti@2.4.1)):
eslint-plugin-toml@0.12.0(eslint@9.19.0(jiti@2.4.1)):
dependencies:
debug: 4.4.0
eslint: 9.18.0(jiti@2.4.1)
eslint-compat-utils: 0.6.4(eslint@9.18.0(jiti@2.4.1))
eslint: 9.19.0(jiti@2.4.1)
eslint-compat-utils: 0.6.4(eslint@9.19.0(jiti@2.4.1))
lodash: 4.17.21
toml-eslint-parser: 0.10.0
transitivePeerDependencies:
- supports-color
eslint-plugin-unicorn@56.0.1(eslint@9.18.0(jiti@2.4.1)):
eslint-plugin-unicorn@56.0.1(eslint@9.19.0(jiti@2.4.1)):
dependencies:
'@babel/helper-validator-identifier': 7.25.9
'@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.1))
'@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.1))
ci-info: 4.1.0
clean-regexp: 1.0.0
core-js-compat: 3.39.0
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
esquery: 1.6.0
globals: 15.14.0
indent-string: 4.0.0
@ -7305,41 +7297,41 @@ snapshots:
semver: 7.6.3
strip-indent: 3.0.0
eslint-plugin-unused-imports@4.1.4(@typescript-eslint/eslint-plugin@8.21.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.1)):
eslint-plugin-unused-imports@4.1.4(@typescript-eslint/eslint-plugin@8.23.0(@typescript-eslint/parser@8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.1)):
dependencies:
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
optionalDependencies:
'@typescript-eslint/eslint-plugin': 8.21.0(@typescript-eslint/parser@8.21.0(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.18.0(jiti@2.4.1))(typescript@5.7.3)
'@typescript-eslint/eslint-plugin': 8.23.0(@typescript-eslint/parser@8.23.0(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3))(eslint@9.19.0(jiti@2.4.1))(typescript@5.7.3)
eslint-plugin-vue@9.32.0(eslint@9.18.0(jiti@2.4.1)):
eslint-plugin-vue@9.32.0(eslint@9.19.0(jiti@2.4.1)):
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.1))
eslint: 9.18.0(jiti@2.4.1)
'@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.1))
eslint: 9.19.0(jiti@2.4.1)
globals: 13.24.0
natural-compare: 1.4.0
nth-check: 2.1.1
postcss-selector-parser: 6.1.2
semver: 7.6.3
vue-eslint-parser: 9.4.3(eslint@9.18.0(jiti@2.4.1))
vue-eslint-parser: 9.4.3(eslint@9.19.0(jiti@2.4.1))
xml-name-validator: 4.0.0
transitivePeerDependencies:
- supports-color
eslint-plugin-yml@1.16.0(eslint@9.18.0(jiti@2.4.1)):
eslint-plugin-yml@1.16.0(eslint@9.19.0(jiti@2.4.1)):
dependencies:
debug: 4.4.0
eslint: 9.18.0(jiti@2.4.1)
eslint-compat-utils: 0.6.4(eslint@9.18.0(jiti@2.4.1))
eslint: 9.19.0(jiti@2.4.1)
eslint-compat-utils: 0.6.4(eslint@9.19.0(jiti@2.4.1))
lodash: 4.17.21
natural-compare: 1.4.0
yaml-eslint-parser: 1.2.3
transitivePeerDependencies:
- supports-color
eslint-processor-vue-blocks@1.0.0(@vue/compiler-sfc@3.5.13)(eslint@9.18.0(jiti@2.4.1)):
eslint-processor-vue-blocks@1.0.0(@vue/compiler-sfc@3.5.13)(eslint@9.19.0(jiti@2.4.1)):
dependencies:
'@vue/compiler-sfc': 3.5.13
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
eslint-scope@5.1.1:
dependencies:
@ -7362,14 +7354,14 @@ snapshots:
eslint-visitor-keys@4.2.0: {}
eslint@9.18.0(jiti@2.4.1):
eslint@9.19.0(jiti@2.4.1):
dependencies:
'@eslint-community/eslint-utils': 4.4.1(eslint@9.18.0(jiti@2.4.1))
'@eslint-community/eslint-utils': 4.4.1(eslint@9.19.0(jiti@2.4.1))
'@eslint-community/regexpp': 4.12.1
'@eslint/config-array': 0.19.1
'@eslint/core': 0.10.0
'@eslint/eslintrc': 3.2.0
'@eslint/js': 9.18.0
'@eslint/js': 9.19.0
'@eslint/plugin-kit': 0.2.5
'@humanfs/node': 0.16.6
'@humanwhocodes/module-importer': 1.0.1
@ -7495,8 +7487,6 @@ snapshots:
dependencies:
array-back: 3.1.0
find-up-simple@1.0.0: {}
find-up@4.1.0:
dependencies:
locate-path: 5.0.0
@ -9087,11 +9077,11 @@ snapshots:
totalist@3.0.1: {}
ts-api-utils@1.4.3(typescript@5.7.3):
ts-api-utils@2.0.0(typescript@5.7.3):
dependencies:
typescript: 5.7.3
ts-api-utils@2.0.0(typescript@5.7.3):
ts-api-utils@2.0.1(typescript@5.7.3):
dependencies:
typescript: 5.7.3
@ -9387,10 +9377,10 @@ snapshots:
dompurify: 3.2.3
vue: 3.5.13(typescript@5.7.3)
vue-eslint-parser@9.4.3(eslint@9.18.0(jiti@2.4.1)):
vue-eslint-parser@9.4.3(eslint@9.19.0(jiti@2.4.1)):
dependencies:
debug: 4.4.0
eslint: 9.18.0(jiti@2.4.1)
eslint: 9.19.0(jiti@2.4.1)
eslint-scope: 7.2.2
eslint-visitor-keys: 3.4.3
espree: 9.6.1

View file

@ -4,7 +4,6 @@ import gettext from '@/gettext'
import { useSettingsStore } from '@/pinia'
import { theme } from 'ant-design-vue'
import en_US from 'ant-design-vue/es/locale/en_US'
import zh_CN from 'ant-design-vue/es/locale/zh_CN'
import zh_TW from 'ant-design-vue/es/locale/zh_TW'
// This starter template is using Vue 3 <script setup> SFCs

View file

@ -181,7 +181,7 @@ function handleBatchUpdated() {
v-if="!disableAdd && !inTrash"
type="link"
size="small"
@click="add"
@click="add()"
>
{{ $gettext('Add') }}
</AButton>

View file

@ -1 +1 @@
{"version":"2.0.0-rc.1","build_id":1,"total_build":375}
{"version":"2.0.0-rc.1","build_id":7,"total_build":381}

View file

@ -185,7 +185,7 @@ function wsOnMessage(m: MessageEvent) {
</p>
<p>
{{ $gettext('Load Average:') }}
<span class="load-avg-describe"> 1min:</span>{{ ` ${loadavg?.load1?.toFixed(2)}` }}
<span class="load-avg-describe"> 1min:</span>{{ loadavg?.load1?.toFixed(2) }}
<span class="load-avg-describe"> | 5min:</span>{{ loadavg?.load5?.toFixed(2) }}
<span class="load-avg-describe"> | 15min:</span>{{ loadavg?.load15?.toFixed(2) }}
</p>
@ -440,6 +440,7 @@ function wsOnMessage(m: MessageEvent) {
}
.load-avg-describe {
margin-right: 2px;
@media (max-width: 1600px) and (min-width: 1200px) {
display: none;
}

View file

@ -6,6 +6,7 @@ import BatchUpgrader from '@/views/environment/BatchUpgrader.vue'
import envColumns from '@/views/environment/envColumns'
import { message } from 'ant-design-vue'
const route = useRoute()
const curd = ref()
function loadFromSettings() {
environment.load_from_settings().then(() => {
@ -20,6 +21,18 @@ const refUpgrader = ref()
function batchUpgrade() {
refUpgrader.value.open(selectedNodeIds, selectedNodes)
}
const inTrash = computed(() => {
return route.query.trash === 'true'
})
// const timer = setInterval(() => {
// curd.value.get_list()
// }, 10000)
// onUnmounted(() => {
// clearInterval(timer)
// })
</script>
<template>
@ -43,7 +56,7 @@ function batchUpgrade() {
<BatchUpgrader ref="refUpgrader" />
<FooterToolBar>
<FooterToolBar v-if="!inTrash">
<ATooltip
:title="$gettext('Please select at least one node to upgrade')"
placement="topLeft"

View file

@ -26,12 +26,12 @@ const columns: Column[] = [{
placeholder: () => 'https://10.0.0.1:9000',
},
},
width: 300,
width: 260,
}, {
title: () => $gettext('Version'),
dataIndex: 'version',
pithy: true,
width: 150,
width: 120,
}, {
title: () => 'NodeSecret',
dataIndex: 'token',
@ -65,7 +65,7 @@ const columns: Column[] = [{
},
sorter: true,
pithy: true,
width: 200,
width: 120,
}, {
title: () => $gettext('Enabled'),
dataIndex: 'enabled',
@ -85,7 +85,7 @@ const columns: Column[] = [{
},
sorter: true,
pithy: true,
width: 150,
width: 120,
}, {
title: () => $gettext('Updated at'),
dataIndex: 'updated_at',

View file

@ -8,6 +8,7 @@ const props = defineProps<{
configName: string
currentServerIndex: number
certInfo?: CertificateInfo[]
siteEnabled: boolean
}>()
const enabled = defineModel<boolean>('enabled', {
@ -68,6 +69,7 @@ function handleCertChange(certs: Cert[]) {
<ChangeCert @change="handleCertChange" />
<IssueCert
v-if="siteEnabled"
v-model:enabled="enabled"
:config-name="configName"
/>

View file

@ -120,15 +120,15 @@ provide('ngx_directives', ngx_directives)
/>
<div class="tab-content">
<template v-if="current_support_ssl && enabled">
<Cert
v-if="current_support_ssl"
v-model:enabled="autoCert"
:config-name="ngx_config.name"
:cert-info="certInfo?.[k]"
:current-server-index="current_server_index"
/>
</template>
<Cert
v-if="current_support_ssl"
v-model:enabled="autoCert"
class="mb-4"
:site-enabled="enabled"
:config-name="ngx_config.name"
:cert-info="certInfo?.[k]"
:current-server-index="current_server_index"
/>
<template v-if="v.comments">
<h3>{{ $gettext('Comments') }}</h3>

View file

@ -1,3 +1,4 @@
import { Agent } from 'node:http'
import { fileURLToPath, URL } from 'node:url'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
@ -81,6 +82,22 @@ export default defineConfig(({ mode }) => {
changeOrigin: true,
secure: false,
ws: true,
timeout: 5000,
agent: new Agent({
keepAlive: false,
}),
onProxyReq(proxyReq, req) {
proxyReq.setHeader('Connection', 'keep-alive')
if (req.headers.accept === 'text/event-stream') {
proxyReq.setHeader('Cache-Control', 'no-cache')
proxyReq.setHeader('Content-Type', 'text/event-stream')
}
},
onProxyReqWs(proxyReq, req, socket) {
socket.on('close', () => {
proxyReq.destroy()
})
},
},
},
},

View file

@ -1,12 +1,12 @@
import {LocaleSpecificConfig, DefaultTheme} from 'vitepress'
import {demoUrl} from './common'
import { LocaleSpecificConfig, DefaultTheme } from 'vitepress'
import { demoUrl } from './common'
export const enConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
themeConfig: {
nav: [
{text: 'Home', link: '/'},
{text: 'Guide', link: '/guide/about'},
{text: 'Demo', link: demoUrl}
{ text: 'Home', link: '/' },
{ text: 'Guide', link: '/guide/about' },
{ text: 'Demo', link: demoUrl }
],
sidebar: {
@ -15,55 +15,56 @@ export const enConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
text: 'Introduction',
collapsed: false,
items: [
{text: 'What is Nginx UI?', link: '/guide/about'},
{text: 'Getting Started', link: '/guide/getting-started'},
{text: 'Install Script', link: '/guide/install-script-linux'}
{ text: 'What is Nginx UI?', link: '/guide/about' },
{ text: 'Getting Started', link: '/guide/getting-started' },
{ text: 'Install Script', link: '/guide/install-script-linux' }
]
},
{
text: 'Development',
collapsed: false,
items: [
{text: 'Build', link: '/guide/build'},
{text: 'Project Structure', link: '/guide/project-structure'},
{text: 'Config Template', link: '/guide/nginx-ui-template'},
{text: 'Contributing', link: '/guide/contributing'}
{ text: 'Devcontainer', link: '/guide/devcontainer' },
{ text: 'Build', link: '/guide/build' },
{ text: 'Project Structure', link: '/guide/project-structure' },
{ text: 'Config Template', link: '/guide/nginx-ui-template' },
{ text: 'Contributing', link: '/guide/contributing' }
]
},
{
text: 'Configuration',
collapsed: false,
items: [
{text: 'App', link: '/guide/config-app'},
{text: 'Server', link: '/guide/config-server'},
{text: 'Database', link: '/guide/config-database'},
{text: 'Auth', link: '/guide/config-auth'},
{text: 'Casdoor', link: '/guide/config-casdoor'},
{text: 'Cert', link: '/guide/config-cert'},
{text: 'Cluster', link: '/guide/config-cluster'},
{text: 'Crypto', link: '/guide/config-crypto'},
{text: 'Http', link: '/guide/config-http'},
{text: 'Logrotate', link: '/guide/config-logrotate'},
{text: 'Nginx', link: '/guide/config-nginx'},
{text: 'Node', link: '/guide/config-node'},
{text: 'Open AI', link: '/guide/config-openai'},
{text: 'Terminal', link: '/guide/config-terminal'},
{text: 'Webauthn', link: '/guide/config-webauthn'}
{ text: 'App', link: '/guide/config-app' },
{ text: 'Server', link: '/guide/config-server' },
{ text: 'Database', link: '/guide/config-database' },
{ text: 'Auth', link: '/guide/config-auth' },
{ text: 'Casdoor', link: '/guide/config-casdoor' },
{ text: 'Cert', link: '/guide/config-cert' },
{ text: 'Cluster', link: '/guide/config-cluster' },
{ text: 'Crypto', link: '/guide/config-crypto' },
{ text: 'Http', link: '/guide/config-http' },
{ text: 'Logrotate', link: '/guide/config-logrotate' },
{ text: 'Nginx', link: '/guide/config-nginx' },
{ text: 'Node', link: '/guide/config-node' },
{ text: 'Open AI', link: '/guide/config-openai' },
{ text: 'Terminal', link: '/guide/config-terminal' },
{ text: 'Webauthn', link: '/guide/config-webauthn' }
]
},
{
text: 'Environment Variables',
collapsed: false,
items: [
{text: 'Reference', link: '/guide/env'},
{ text: 'Reference', link: '/guide/env' },
]
},
{
text: 'Appendix',
collapsed: false,
items: [
{text: 'Nginx Proxy Example', link: '/guide/nginx-proxy-example'},
{text: 'License', link: '/guide/license'}
{ text: 'Nginx Proxy Example', link: '/guide/nginx-proxy-example' },
{ text: 'License', link: '/guide/license' }
]
}
]

View file

@ -1,8 +1,8 @@
import { defineConfig } from 'vitepress'
import {projectUrl, editLinkPattern} from './common'
import { projectUrl, editLinkPattern } from './common'
export const commitRef = process.env.COMMIT_REF ?
`<a href="${projectUrl}/commit/${process.env.COMMIT_REF}">` + process.env.COMMIT_REF.slice(0, 8) + '</a>':
`<a href="${projectUrl}/commit/${process.env.COMMIT_REF}">` + process.env.COMMIT_REF.slice(0, 8) + '</a>' :
'dev'
function thisYear() {
@ -37,7 +37,13 @@ export const sharedConfig = defineConfig({
},
socialLinks: [
{icon: 'github', link: projectUrl}
{ icon: 'github', link: projectUrl }
]
},
vite: {
server: {
port: Number.parseInt(process.env.VITE_PORT ?? '3003')
}
}
})

View file

@ -1,12 +1,12 @@
import {LocaleSpecificConfig, DefaultTheme} from 'vitepress'
import {demoUrl, editLinkPattern} from './common'
import { LocaleSpecificConfig, DefaultTheme } from 'vitepress'
import { demoUrl, editLinkPattern } from './common'
export const zhCNConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
themeConfig: {
nav: [
{text: '首页', link: '/zh_CN/'},
{text: '手册', link: '/zh_CN/guide/about'},
{text: '演示', link: demoUrl}
{ text: '首页', link: '/zh_CN/' },
{ text: '手册', link: '/zh_CN/guide/about' },
{ text: '演示', link: demoUrl }
],
editLink: {
@ -20,55 +20,56 @@ export const zhCNConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
text: '介绍',
collapsed: false,
items: [
{text: '何为 Nginx UI?', link: '/zh_CN/guide/about'},
{text: '即刻开始', link: '/zh_CN/guide/getting-started'},
{text: '安装脚本', link: '/zh_CN/guide/install-script-linux'}
{ text: '何为 Nginx UI?', link: '/zh_CN/guide/about' },
{ text: '即刻开始', link: '/zh_CN/guide/getting-started' },
{ text: '安装脚本', link: '/zh_CN/guide/install-script-linux' }
]
},
{
text: '开发',
collapsed: false,
items: [
{text: '构建', link: '/zh_CN/guide/build'},
{text: '项目结构', link: '/zh_CN/guide/project-structure'},
{text: '配置模板', link: '/zh_CN/guide/nginx-ui-template'},
{text: '贡献代码', link: '/zh_CN/guide/contributing'}
{ text: '开发容器', link: '/zh_CN/guide/devcontainer' },
{ text: '构建', link: '/zh_CN/guide/build' },
{ text: '项目结构', link: '/zh_CN/guide/project-structure' },
{ text: '配置模板', link: '/zh_CN/guide/nginx-ui-template' },
{ text: '贡献代码', link: '/zh_CN/guide/contributing' }
]
},
{
text: '配置',
collapsed: false,
items: [
{text: 'App', link: '/zh_CN/guide/config-app'},
{text: 'Server', link: '/zh_CN/guide/config-server'},
{text: 'Database', link: '/zh_CN/guide/config-database'},
{text: 'Auth', link: '/zh_CN/guide/config-auth'},
{text: 'Casdoor', link: '/zh_CN/guide/config-casdoor'},
{text: 'Cert', link: '/zh_CN/guide/config-cert'},
{text: 'Cluster', link: '/zh_CN/guide/config-cluster'},
{text: 'Crypto', link: '/zh_CN/guide/config-crypto'},
{text: 'Http', link: '/zh_CN/guide/config-http'},
{text: 'Logrotate', link: '/zh_CN/guide/config-logrotate'},
{text: 'Nginx', link: '/zh_CN/guide/config-nginx'},
{text: 'Node', link: '/zh_CN/guide/config-node'},
{text: 'Open AI', link: '/zh_CN/guide/config-openai'},
{text: 'Terminal', link: '/zh_CN/guide/config-terminal'},
{text: 'Webauthn', link: '/zh_CN/guide/config-webauthn'}
{ text: 'App', link: '/zh_CN/guide/config-app' },
{ text: 'Server', link: '/zh_CN/guide/config-server' },
{ text: 'Database', link: '/zh_CN/guide/config-database' },
{ text: 'Auth', link: '/zh_CN/guide/config-auth' },
{ text: 'Casdoor', link: '/zh_CN/guide/config-casdoor' },
{ text: 'Cert', link: '/zh_CN/guide/config-cert' },
{ text: 'Cluster', link: '/zh_CN/guide/config-cluster' },
{ text: 'Crypto', link: '/zh_CN/guide/config-crypto' },
{ text: 'Http', link: '/zh_CN/guide/config-http' },
{ text: 'Logrotate', link: '/zh_CN/guide/config-logrotate' },
{ text: 'Nginx', link: '/zh_CN/guide/config-nginx' },
{ text: 'Node', link: '/zh_CN/guide/config-node' },
{ text: 'Open AI', link: '/zh_CN/guide/config-openai' },
{ text: 'Terminal', link: '/zh_CN/guide/config-terminal' },
{ text: 'Webauthn', link: '/zh_CN/guide/config-webauthn' }
]
},
{
text: '环境变量',
collapsed: false,
items: [
{text: '参考手册', link: '/zh_CN/guide/env'},
{ text: '参考手册', link: '/zh_CN/guide/env' },
]
},
{
text: '附录',
collapsed: false,
items: [
{text: 'Nginx 代理示例', link: '/zh_CN/guide/nginx-proxy-example'},
{text: '开源协议', link: '/zh_CN/guide/license'}
{ text: 'Nginx 代理示例', link: '/zh_CN/guide/nginx-proxy-example' },
{ text: '开源协议', link: '/zh_CN/guide/license' }
]
}
]

View file

@ -1,12 +1,12 @@
import {LocaleSpecificConfig, DefaultTheme} from 'vitepress'
import {demoUrl, editLinkPattern} from './common'
import { LocaleSpecificConfig, DefaultTheme } from 'vitepress'
import { demoUrl, editLinkPattern } from './common'
export const zhTWConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
themeConfig: {
nav: [
{text: '首頁', link: '/zh_TW/'},
{text: '手冊', link: '/zh_TW/guide/about'},
{text: '演示', link: demoUrl}
{ text: '首頁', link: '/zh_TW/' },
{ text: '手冊', link: '/zh_TW/guide/about' },
{ text: '演示', link: demoUrl }
],
editLink: {
@ -20,55 +20,56 @@ export const zhTWConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
text: '介紹',
collapsed: false,
items: [
{text: '何為 Nginx UI?', link: '/zh_TW/guide/about'},
{text: '即刻開始', link: '/zh_TW/guide/getting-started'},
{text: '安裝指令碼', link: '/zh_TW/guide/install-script-linux'}
{ text: '何為 Nginx UI?', link: '/zh_TW/guide/about' },
{ text: '即刻開始', link: '/zh_TW/guide/getting-started' },
{ text: '安裝指令碼', link: '/zh_TW/guide/install-script-linux' }
]
},
{
text: '開發',
collapsed: false,
items: [
{text: '構建', link: '/zh_TW/guide/build'},
{text: '專案結構', link: '/zh_TW/guide/project-structure'},
{text: '配置模板', link: '/zh_TW/guide/nginx-ui-template'},
{text: '貢獻程式碼', link: '/zh_TW/guide/contributing'}
{ text: '開發容器', link: '/zh_TW/guide/devcontainer' },
{ text: '構建', link: '/zh_TW/guide/build' },
{ text: '專案結構', link: '/zh_TW/guide/project-structure' },
{ text: '配置模板', link: '/zh_TW/guide/nginx-ui-template' },
{ text: '貢獻程式碼', link: '/zh_TW/guide/contributing' }
]
},
{
text: '配置',
collapsed: false,
items: [
{text: 'App', link: '/zh_TW/guide/config-app'},
{text: 'Server', link: '/zh_TW/guide/config-server'},
{text: 'Database', link: '/zh_TW/guide/config-database'},
{text: 'Auth', link: '/zh_TW/guide/config-auth'},
{text: 'Casdoor', link: '/zh_TW/guide/config-casdoor'},
{text: 'Cert', link: '/zh_TW/guide/config-cert'},
{text: 'Cluster', link: '/zh_TW/guide/config-cluster'},
{text: 'Crypto', link: '/zh_TW/guide/config-crypto'},
{text: 'Http', link: '/zh_TW/guide/config-http'},
{text: 'Logrotate', link: '/zh_TW/guide/config-logrotate'},
{text: 'Nginx', link: '/zh_TW/guide/config-nginx'},
{text: 'Node', link: '/zh_TW/guide/config-node'},
{text: 'Open AI', link: '/zh_TW/guide/config-openai'},
{text: 'Terminal', link: '/zh_TW/guide/config-terminal'},
{text: 'Webauthn', link: '/zh_TW/guide/config-webauthn'}
{ text: 'App', link: '/zh_TW/guide/config-app' },
{ text: 'Server', link: '/zh_TW/guide/config-server' },
{ text: 'Database', link: '/zh_TW/guide/config-database' },
{ text: 'Auth', link: '/zh_TW/guide/config-auth' },
{ text: 'Casdoor', link: '/zh_TW/guide/config-casdoor' },
{ text: 'Cert', link: '/zh_TW/guide/config-cert' },
{ text: 'Cluster', link: '/zh_TW/guide/config-cluster' },
{ text: 'Crypto', link: '/zh_TW/guide/config-crypto' },
{ text: 'Http', link: '/zh_TW/guide/config-http' },
{ text: 'Logrotate', link: '/zh_TW/guide/config-logrotate' },
{ text: 'Nginx', link: '/zh_TW/guide/config-nginx' },
{ text: 'Node', link: '/zh_TW/guide/config-node' },
{ text: 'Open AI', link: '/zh_TW/guide/config-openai' },
{ text: 'Terminal', link: '/zh_TW/guide/config-terminal' },
{ text: 'Webauthn', link: '/zh_TW/guide/config-webauthn' }
]
},
{
text: '環境變量',
collapsed: false,
items: [
{text: '參考手冊', link: '/zh_TW/guide/env'},
{ text: '參考手冊', link: '/zh_TW/guide/env' },
]
},
{
text: '附錄',
collapsed: false,
items: [
{text: 'Nginx 代理示例', link: '/zh_TW/guide/nginx-proxy-example'},
{text: '開源協議', link: '/zh_TW/guide/license'}
{ text: 'Nginx 代理示例', link: '/zh_TW/guide/nginx-proxy-example' },
{ text: '開源協議', link: '/zh_TW/guide/license' }
]
}
]

View file

@ -74,11 +74,15 @@ Nginx UI is available on the following platforms:
## Internationalization
We proudly offer official support for:
- English
- Simplified Chinese
- Traditional Chinese
We welcome translations into any language.
As non-native English speakers, we strive for accuracy, but we know theres always room for improvement. If you spot any issues, wed love your feedback!
Thanks to our amazing community, additional languages are also available! Explore and contribute to translations on [Weblate](https://weblate.nginxui.com).
## Built With

View file

@ -0,0 +1,50 @@
# Devcontainer
You'll need to set up a development environment if you want to develop on this project.
## Prerequisites
- Docker
- VSCode (Cursor)
- Git
## Setup
1. Open the Command Palette in VSCode (Cursor)
- Mac: `Cmd`+`Shift`+`P`
- Windows: `Ctrl`+`Shift`+`P`
2. Search for `Dev Containers: Rebuild and Reopen in Container` and click on it
3. Wait for the container to start
4. Open the Command Palette in VSCode (Cursor)
- Mac: `Cmd`+`Shift`+`P`
- Windows: `Ctrl`+`Shift`+`P`
5. Select Tasks: Run Task -> Start all services
6. Wait for the services to start
## Ports
| Port | Service |
|-------|------------------|
| 3002 | App |
| 3003 | Documentation |
| 9000 | API Backend |
## Services
- nginx-ui
- nginx-ui-2
- casdoor
- chaltestsrv
- pebble
## Multi-node development
Add the following enviroment in the main node:
```
name: nginx-ui-2
url: http://nginx-ui-2
token: nginx-ui-2
```

View file

@ -27,7 +27,7 @@ install.sh install [OPTIONS]
### Quick Usage
```shell
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) install
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ install
```
The default listening port is `9000`, and the default HTTP Challenge port is `9180`.
@ -60,12 +60,12 @@ install.sh remove [OPTIONS]
```shell [Remove]
# Remove Nginx UI, except configuration and database files
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) remove
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ remove
```
```shell [Purge]
# Remove all the Nginx UI file, include configuration and database files
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) remove --purge
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ remove --purge
```
:::
@ -85,7 +85,7 @@ install.sh help
### Quick Usage
```shell
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) help
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ help
```
## Control Service

View file

@ -2,7 +2,7 @@
"name": "nginx-ui-docs",
"type": "module",
"scripts": {
"docs:dev": "vitepress dev",
"docs:dev": "vitepress dev --host",
"docs:build": "vitepress build",
"docs:preview": "vitepress preview"
},
@ -11,9 +11,9 @@
"vue": "^3.5.13"
},
"devDependencies": {
"@types/node": "^22.10.8",
"@types/node": "^22.13.1",
"less": "^4.2.2"
},
"license": "AGPL-3.0",
"packageManager": "pnpm@9.15.4+sha512.b2dc20e2fc72b3e18848459b37359a32064663e5627a51e4c74b2c29dd8e8e0491483c3abb40789cfd578bf362fb6ba8261b05f0387d76792ed6e23ea3b1b6a0"
"packageManager": "pnpm@10.2.0+sha512.0d27364e0139c6aadeed65ada153135e0ca96c8da42123bd50047f961339dc7a758fc2e944b428f52be570d1bd3372455c1c65fa2e7aa0bfbf931190f9552001"
}

26
docs/pnpm-lock.yaml generated
View file

@ -10,14 +10,14 @@ importers:
dependencies:
vitepress:
specifier: ^1.6.3
version: 1.6.3(@algolia/client-search@5.15.0)(@types/node@22.10.8)(less@4.2.2)(postcss@8.4.49)(search-insights@2.13.0)
version: 1.6.3(@algolia/client-search@5.15.0)(@types/node@22.13.1)(less@4.2.2)(postcss@8.4.49)(search-insights@2.13.0)
vue:
specifier: ^3.5.13
version: 3.5.13
devDependencies:
'@types/node':
specifier: ^22.10.8
version: 22.10.8
specifier: ^22.13.1
version: 22.13.1
less:
specifier: ^4.2.2
version: 4.2.2
@ -415,8 +415,8 @@ packages:
'@types/mdurl@2.0.0':
resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==}
'@types/node@22.10.8':
resolution: {integrity: sha512-rk+QvAEGsbX/ZPiiyel6hJHNUS9cnSbPWVaZLvE+Er3tLqQFzWMz9JOfWW7XUmKvRPfxJfbl3qYWve+RGXncFw==}
'@types/node@22.13.1':
resolution: {integrity: sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==}
'@types/unist@3.0.3':
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
@ -1176,7 +1176,7 @@ snapshots:
'@types/mdurl@2.0.0': {}
'@types/node@22.10.8':
'@types/node@22.13.1':
dependencies:
undici-types: 6.20.0
@ -1186,9 +1186,9 @@ snapshots:
'@ungap/structured-clone@1.2.0': {}
'@vitejs/plugin-vue@5.2.1(vite@5.4.14(@types/node@22.10.8)(less@4.2.2))(vue@3.5.13)':
'@vitejs/plugin-vue@5.2.1(vite@5.4.14(@types/node@22.13.1)(less@4.2.2))(vue@3.5.13)':
dependencies:
vite: 5.4.14(@types/node@22.10.8)(less@4.2.2)
vite: 5.4.14(@types/node@22.13.1)(less@4.2.2)
vue: 3.5.13
'@vue/compiler-core@3.5.13':
@ -1629,17 +1629,17 @@ snapshots:
'@types/unist': 3.0.3
vfile-message: 4.0.2
vite@5.4.14(@types/node@22.10.8)(less@4.2.2):
vite@5.4.14(@types/node@22.13.1)(less@4.2.2):
dependencies:
esbuild: 0.21.5
postcss: 8.4.49
rollup: 4.27.4
optionalDependencies:
'@types/node': 22.10.8
'@types/node': 22.13.1
fsevents: 2.3.3
less: 4.2.2
vitepress@1.6.3(@algolia/client-search@5.15.0)(@types/node@22.10.8)(less@4.2.2)(postcss@8.4.49)(search-insights@2.13.0):
vitepress@1.6.3(@algolia/client-search@5.15.0)(@types/node@22.13.1)(less@4.2.2)(postcss@8.4.49)(search-insights@2.13.0):
dependencies:
'@docsearch/css': 3.8.2
'@docsearch/js': 3.8.2(@algolia/client-search@5.15.0)(search-insights@2.13.0)
@ -1648,7 +1648,7 @@ snapshots:
'@shikijs/transformers': 2.1.0
'@shikijs/types': 2.1.0
'@types/markdown-it': 14.1.2
'@vitejs/plugin-vue': 5.2.1(vite@5.4.14(@types/node@22.10.8)(less@4.2.2))(vue@3.5.13)
'@vitejs/plugin-vue': 5.2.1(vite@5.4.14(@types/node@22.13.1)(less@4.2.2))(vue@3.5.13)
'@vue/devtools-api': 7.7.0
'@vue/shared': 3.5.13
'@vueuse/core': 12.5.0
@ -1657,7 +1657,7 @@ snapshots:
mark.js: 8.11.1
minisearch: 7.1.1
shiki: 2.1.0
vite: 5.4.14(@types/node@22.10.8)(less@4.2.2)
vite: 5.4.14(@types/node@22.13.1)(less@4.2.2)
vue: 3.5.13
optionalDependencies:
postcss: 8.4.49

View file

@ -71,11 +71,15 @@ Nginx UI 可在以下平台中使用:
## 国际化
我们官方支持以下语言:
- 英语
- 简体中文
- 繁体中文
我们欢迎您将项目翻译成任何语言。
由于我们并非英语母语者,尽管已尽力确保准确性,但仍可能存在改进空间。如果您发现任何问题,欢迎向我们反馈!
此外,感谢我们优秀的社区提供了更多语言,欢迎访问 [Weblate](https://weblate.nginxui.com) 进行查看和贡献翻译。
## 构建基于

View file

@ -0,0 +1,48 @@
# 开发容器
如果您想参与本项目开发,需要设置开发环境。
## 前提条件
- Docker
- VSCode (Cursor)
- Git
## 设置步骤
1. 在 VSCode (Cursor) 中打开命令面板
- Mac: `Cmd`+`Shift`+`P`
- Windows: `Ctrl`+`Shift`+`P`
2. 搜索 `Dev Containers: 重新生成并重新打开容器` 并点击
3. 等待容器启动
4. 再次打开命令面板
- Mac: `Cmd`+`Shift`+`P`
- Windows: `Ctrl`+`Shift`+`P`
5. 选择 任务: 运行任务 -> 启动所有服务
6. 等待所有服务启动完成
## 端口映射
| 端口 | 服务 |
|-------|-------------------|
| 3002 | 主应用 |
| 3003 | 文档 |
| 9000 | API 后端 |
## 服务列表
- nginx-ui
- nginx-ui-2
- casdoor
- chaltestsrv
- pebble
## 多节点开发
在主节点中添加以下环境配置:
```
name: nginx-ui-2
url: http://nginx-ui-2
token: nginx-ui-2
```

View file

@ -26,7 +26,7 @@ install.sh install [OPTIONS]
### 快速使用
```shell
bash <(curl -L -s https://mirror.ghproxy.com/https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) install -r https://mirror.ghproxy.com/
bash -c "$(curl -L https://mirror.ghproxy.com/https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ install -r https://mirror.ghproxy.com/
```
一键安装脚本默认设置的监听端口为 `9000`HTTP Challenge 端口默认为 `9180`。如果有端口冲突,请手动修改 `/usr/local/etc/nginx-ui/app.ini`
@ -56,12 +56,12 @@ install.sh remove [OPTIONS]
```shell [移除]
# 删除 Nginx UI但不包括配置和数据库文件
bash <(curl -L -s https://mirror.ghproxy.com/https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) remove
bash -c "$(curl -L https://mirror.ghproxy.com/https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ remove
```
```shell [清除]
# 删除所有 Nginx UI 文件,包括配置和数据库文件
bash <(curl -L -s https://mirror.ghproxy.com/https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) remove --purge
bash -c "$(curl -L https://mirror.ghproxy.com/https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ remove --purge
```
:::
@ -81,7 +81,7 @@ install.sh help
### 快速使用
```shell
bash <(curl -L -s https://mirror.ghproxy.com/https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) help
bash -c "$(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ help
```
## 控制服务

View file

@ -71,11 +71,15 @@ Nginx UI 可在以下作業系統中使用:
## 國際化
- 英語
- 簡體中文
- 繁體中文
我們目前官方支援以下語言:
我們歡迎您將專案翻譯成任何語言。
- 英文
- 簡體中文
- 正体中文
由於我們並非英文母語者,儘管已盡力確保準確性,仍可能有改進的空間。若您發現任何問題,歡迎提供回饋!
此外,感謝熱心的社群貢獻更多語言支援,歡迎前往 [Weblate](https://weblate.nginxui.com) 瀏覽並參與翻譯,共同打造更完善的多語言體驗!
## 構建基於

View file

@ -0,0 +1,48 @@
# 開發容器
如果您想參與本專案開發,需要設定開發環境。
## 必要條件
- Docker
- VSCode (Cursor)
- Git
## 設定步驟
1. 在 VSCode (Cursor) 中開啟指令面板
- Mac: `Cmd`+`Shift`+`P`
- Windows: `Ctrl`+`Shift`+`P`
2. 搜尋 `Dev Containers: 重新產生並重新開啟容器` 並點擊
3. 等待容器啟動
4. 再次開啟指令面板
- Mac: `Cmd`+`Shift`+`P`
- Windows: `Ctrl`+`Shift`+`P`
5. 選擇 任務: 執行任務 -> 啟動所有服務
6. 等待所有服務啟動完成
## 連接埠映射
| 連接埠 | 服務 |
|-------|-------------------|
| 3002 | 主應用 |
| 3003 | 文件 |
| 9000 | API 後端 |
## 服務清單
- nginx-ui
- nginx-ui-2
- casdoor
- chaltestsrv
- pebble
## 多節點開發
在主節點中新增以下環境設定:
```
name: nginx-ui-2
url: http://nginx-ui-2
token: nginx-ui-2
```

View file

@ -26,7 +26,7 @@ install.sh install [OPTIONS]
### 快速使用
```shell
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) install
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ install
```
安裝指令碼預設的監聽埠為 `9000`HTTP Challenge 埠預設為 `9180`。如果出現埠衝突請修改 `/usr/local/etc/nginx-ui/app.ini`
@ -56,12 +56,12 @@ install.sh remove [OPTIONS]
```shell [移除]
# 解除安裝 Nginx UI 但保留配置和資料庫檔案
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) remove
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ remove
```
```shell [清除]
# 解除安裝並刪除所有 Nginx UI 檔案,包括配置和資料庫檔案
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) remove --purge
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ remove --purge
```
:::
@ -81,7 +81,7 @@ install.sh help
### 快速使用
```shell
bash <(curl -L -s https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh) help
bash -c "$(curl -L https://raw.githubusercontent.com/0xJacky/nginx-ui/main/install.sh)" @ help
```
## 控制服務

4
go.mod
View file

@ -11,7 +11,6 @@ require (
github.com/dgraph-io/ristretto/v2 v2.1.0
github.com/dustin/go-humanize v1.0.1
github.com/elliotchance/orderedmap/v3 v3.1.0
github.com/fatih/color v1.18.0
github.com/gin-contrib/static v1.1.3
github.com/gin-gonic/gin v1.10.0
github.com/go-acme/lego/v4 v4.21.0
@ -38,7 +37,6 @@ require (
github.com/uozi-tech/cosy v1.14.3
github.com/uozi-tech/cosy-driver-sqlite v0.2.0
github.com/urfave/cli/v3 v3.0.0-beta1
go.uber.org/zap v1.27.0
golang.org/x/crypto v0.32.0
golang.org/x/net v0.34.0
gopkg.in/ini.v1 v1.67.0
@ -108,6 +106,7 @@ require (
github.com/dnsimple/dnsimple-go v1.7.0 // indirect
github.com/ebitengine/purego v0.8.2 // indirect
github.com/exoscale/egoscale/v3 v3.1.9 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
@ -254,6 +253,7 @@ require (
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/ratelimit v0.3.1 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/arch v0.13.0 // indirect
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c // indirect
golang.org/x/mod v0.22.0 // indirect

View file

@ -3,10 +3,11 @@ package cert
import (
"crypto/x509"
"encoding/pem"
"github.com/0xJacky/Nginx-UI/internal/helper"
"github.com/0xJacky/Nginx-UI/internal/nginx"
"os"
"time"
"github.com/0xJacky/Nginx-UI/internal/helper"
"github.com/0xJacky/Nginx-UI/internal/nginx"
)
type Info struct {
@ -39,8 +40,19 @@ func GetCertInfo(sslCertificatePath string) (info *Info, err error) {
return
}
// for wildcard certificate, the subject name is the first DNS name
subjectName := cert.Subject.CommonName
if subjectName == "" {
for _, name := range cert.DNSNames {
if name != "" {
subjectName = name
break
}
}
}
info = &Info{
SubjectName: cert.Subject.CommonName,
SubjectName: subjectName,
IssuerName: cert.Issuer.CommonName,
NotAfter: cert.NotAfter,
NotBefore: cert.NotBefore,

View file

@ -1,10 +1,11 @@
package cert
import (
"github.com/0xJacky/Nginx-UI/internal/helper"
"github.com/0xJacky/Nginx-UI/internal/nginx"
"os"
"path/filepath"
"github.com/0xJacky/Nginx-UI/internal/helper"
"github.com/0xJacky/Nginx-UI/internal/nginx"
)
type Content struct {
@ -33,25 +34,25 @@ func (c *Content) WriteFile() (err error) {
// The permission bits perm (before umask) are used for all directories that MkdirAll creates.
// If path is already a directory, MkdirAll does nothing and returns nil.
err = os.MkdirAll(filepath.Dir(c.SSLCertificatePath), 0644)
err = os.MkdirAll(filepath.Dir(c.SSLCertificatePath), 0755)
if err != nil {
return
}
err = os.MkdirAll(filepath.Dir(c.SSLCertificateKeyPath), 0644)
err = os.MkdirAll(filepath.Dir(c.SSLCertificateKeyPath), 0755)
if err != nil {
return
}
if c.SSLCertificate != "" {
err = os.WriteFile(c.SSLCertificatePath, []byte(c.SSLCertificate), 0644)
err = os.WriteFile(c.SSLCertificatePath, []byte(c.SSLCertificate), 0755)
if err != nil {
return
}
}
if c.SSLCertificateKey != "" {
err = os.WriteFile(c.SSLCertificateKeyPath, []byte(c.SSLCertificateKey), 0644)
err = os.WriteFile(c.SSLCertificateKeyPath, []byte(c.SSLCertificateKey), 0755)
if err != nil {
return
}

View file

@ -1,27 +0,0 @@
package logger
import (
"github.com/fatih/color"
"go.uber.org/zap/zapcore"
)
func colorLevelEncoder(l zapcore.Level, enc zapcore.PrimitiveArrayEncoder) {
colorLevel := color.New()
switch l {
case zapcore.DebugLevel:
colorLevel.Add(color.FgCyan)
case zapcore.InfoLevel:
colorLevel.Add(color.FgGreen)
case zapcore.WarnLevel:
colorLevel.Add(color.FgYellow)
case zapcore.ErrorLevel, zapcore.DPanicLevel:
colorLevel.Add(color.FgHiRed)
case zapcore.PanicLevel, zapcore.FatalLevel:
colorLevel.Add(color.FgRed)
default:
colorLevel.Add(color.Reset)
}
enc.AppendString(colorLevel.Sprint(l.CapitalString()))
}

View file

@ -1,103 +0,0 @@
package logger
import (
"github.com/0xJacky/Nginx-UI/settings"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"os"
)
var logger *zap.SugaredLogger
func init() {
// First, define our level-handling logic.
highPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl >= zapcore.ErrorLevel
})
lowPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
switch settings.ServerSettings.RunMode {
case gin.ReleaseMode:
return lvl >= zapcore.InfoLevel && lvl < zapcore.ErrorLevel
default:
fallthrough
case gin.DebugMode:
return lvl < zapcore.ErrorLevel
}
})
// Directly output to stdout and stderr, and add caller information.
consoleDebugging := zapcore.Lock(os.Stdout)
consoleErrors := zapcore.Lock(os.Stderr)
encoderConfig := zap.NewDevelopmentEncoderConfig()
encoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05")
encoderConfig.ConsoleSeparator = "\t"
encoderConfig.EncodeLevel = colorLevelEncoder
consoleEncoder := zapcore.NewConsoleEncoder(encoderConfig)
// Join the outputs, encoders, and level-handling functions into
// zapcore.Cores, then tee the two cores together.
core := zapcore.NewTee(
zapcore.NewCore(consoleEncoder, consoleErrors, highPriority),
zapcore.NewCore(consoleEncoder, consoleDebugging, lowPriority),
)
// From a zapcore.Core, it's easy to construct a Logger.
logger = zap.New(core, zap.AddCaller()).WithOptions(zap.AddCallerSkip(1)).Sugar()
}
func Sync() {
_ = logger.Sync()
}
func GetLogger() *zap.SugaredLogger {
return logger
}
func Info(args ...interface{}) {
logger.Infoln(args...)
}
func Error(args ...interface{}) {
logger.Errorln(args...)
}
func Fatal(args ...interface{}) {
logger.Fatalln(args...)
}
func Warn(args ...interface{}) {
logger.Warnln(args...)
}
func Debug(args ...interface{}) {
logger.Debugln(args...)
}
func DPanic(args ...interface{}) {
logger.DPanic(args...)
}
func Infof(format string, args ...interface{}) {
logger.Infof(format, args...)
}
func Errorf(format string, args ...interface{}) {
logger.Errorf(format, args...)
}
func Fatalf(format string, args ...interface{}) {
logger.Fatalf(format, args...)
}
func DPanicf(format string, args ...interface{}) {
logger.DPanicf(format, args...)
}
func Warnf(format string, args ...interface{}) {
logger.Warnf(format, args...)
}
func Debugf(format string, args ...interface{}) {
logger.Debugf(format, args...)
}

View file

@ -0,0 +1,29 @@
//go:build !unembed
package middleware
import (
"io/fs"
"net/http"
"path"
"github.com/0xJacky/Nginx-UI/app"
"github.com/gin-contrib/static"
"github.com/uozi-tech/cosy/logger"
)
func MustFs(dir string) (serverFileSystem static.ServeFileSystem) {
sub, err := fs.Sub(app.DistFS, path.Join("dist", dir))
if err != nil {
logger.Error(err)
return
}
serverFileSystem = ServerFileSystemType{
http.FS(sub),
}
return
}

View file

@ -2,16 +2,14 @@ package middleware
import (
"encoding/base64"
"github.com/0xJacky/Nginx-UI/app"
"github.com/0xJacky/Nginx-UI/internal/user"
"github.com/0xJacky/Nginx-UI/settings"
"github.com/gin-contrib/static"
"github.com/gin-gonic/gin"
"github.com/uozi-tech/cosy/logger"
"io/fs"
"net/http"
"path"
"strings"
"github.com/0xJacky/Nginx-UI/internal/user"
"github.com/0xJacky/Nginx-UI/settings"
"github.com/gin-gonic/gin"
"github.com/uozi-tech/cosy/logger"
)
func AuthRequired() gin.HandlerFunc {
@ -72,22 +70,6 @@ func (f ServerFileSystemType) Exists(prefix string, _path string) bool {
return err == nil
}
func MustFs(dir string) (serverFileSystem static.ServeFileSystem) {
sub, err := fs.Sub(app.DistFS, path.Join("dist", dir))
if err != nil {
logger.Error(err)
return
}
serverFileSystem = ServerFileSystemType{
http.FS(sub),
}
return
}
func CacheJs() gin.HandlerFunc {
return func(c *gin.Context) {
if strings.Contains(c.Request.URL.String(), "js") {

View file

@ -10,7 +10,7 @@ type Environment struct {
Name string `json:"name"`
URL string `json:"url"`
Token string `json:"token"`
Enabled bool `json:"enabled" gorm:"default:true"`
Enabled bool `json:"enabled" gorm:"default:false"`
}
func (e *Environment) GetUrl(uri string) (decodedUri string, err error) {

View file

@ -1,13 +0,0 @@
#!/bin/bash
if [ "$(ls -A /etc/nginx)" = "" ]; then
echo "Initialing Nginx config dir"
cp -rp /usr/etc/nginx/* /etc/nginx/
echo "Initialed Nginx config dir"
fi
echo "export PATH=$PATH:/usr/local/go/bin:$(go env GOPATH)/bin" >> ~/.profile
source ~/.profile
nginx
cd /app && air

View file

@ -1,9 +0,0 @@
# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse
deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-security main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-security main restricted universe multiverse

View file

@ -1,6 +1,8 @@
package router
import (
"net/http"
"github.com/0xJacky/Nginx-UI/api/analytic"
"github.com/0xJacky/Nginx-UI/api/certificate"
"github.com/0xJacky/Nginx-UI/api/cluster"
@ -19,19 +21,14 @@ import (
"github.com/0xJacky/Nginx-UI/api/upstream"
"github.com/0xJacky/Nginx-UI/api/user"
"github.com/0xJacky/Nginx-UI/internal/middleware"
"github.com/gin-contrib/static"
"github.com/gin-gonic/gin"
"github.com/uozi-tech/cosy"
"net/http"
)
func InitRouter() {
r := cosy.GetEngine()
r.Use(
middleware.CacheJs(),
middleware.IPWhiteList(),
static.Serve("/", middleware.MustFs("")),
)
initEmbedRoute(r)
r.NoRoute(func(c *gin.Context) {
c.JSON(http.StatusNotFound, gin.H{

17
router/routers_embed.go Normal file
View file

@ -0,0 +1,17 @@
//go:build !unembed
package router
import (
"github.com/0xJacky/Nginx-UI/internal/middleware"
"github.com/gin-contrib/static"
"github.com/gin-gonic/gin"
)
func initEmbedRoute(r *gin.Engine) {
r.Use(
middleware.CacheJs(),
middleware.IPWhiteList(),
static.Serve("/", middleware.MustFs("")),
)
}

View file

@ -0,0 +1,8 @@
//go:build unembed
package router
import "github.com/gin-gonic/gin"
func initEmbedRoute(r *gin.Engine) {
}