|
- #!/usr/bin/env bash
-
- if [ -z "${BASH_VERSION:-}" ]; then
- exec bash "$0" "$@"
- fi
-
- set -Eeuo pipefail
-
- APP_NAME="${APP_NAME:-pc_nuxt}"
- BRANCH="${BRANCH:-}"
- NUXT_PUBLIC_API_BASE="${NUXT_PUBLIC_API_BASE:-https://api.aionline.cc}"
- NUXT_API_SERVER_BASE="${NUXT_API_SERVER_BASE:-$NUXT_PUBLIC_API_BASE}"
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-
- export NUXT_PUBLIC_API_BASE
- export NUXT_API_SERVER_BASE
-
- cd "$SCRIPT_DIR"
-
- log() {
- printf '\n[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
- }
-
- require_command() {
- if ! command -v "$1" >/dev/null 2>&1; then
- log "Missing command: $1"
- exit 1
- fi
- }
-
- validate_api_base() {
- node - "$NUXT_PUBLIC_API_BASE" <<'NODE'
- const value = process.argv[2]
- let url
- try {
- url = new URL(value)
- } catch {
- console.error(`[pc_nuxt] Invalid NUXT_PUBLIC_API_BASE: ${value || '(empty)'}`)
- process.exit(1)
- }
- const hostname = url.hostname.toLowerCase()
- const isPrivate = hostname === 'localhost'
- || hostname === '0.0.0.0'
- || /^127\./.test(hostname)
- || hostname === '[::1]'
- || hostname.endsWith('.local')
- || /^10\./.test(hostname)
- || /^192\.168\./.test(hostname)
- || /^169\.254\./.test(hostname)
- || /^172\.(1[6-9]|2\d|3[01])\./.test(hostname)
- if (!['http:', 'https:'].includes(url.protocol) || isPrivate) {
- console.error(`[pc_nuxt] Production API must be a public http(s) URL: ${value}`)
- process.exit(1)
- }
- NODE
- }
-
- validate_server_api_base() {
- node - "$NUXT_API_SERVER_BASE" <<'NODE'
- const value = process.argv[2]
- let url
- try {
- url = new URL(value)
- } catch {
- console.error(`[pc_nuxt] Invalid NUXT_API_SERVER_BASE: ${value || '(empty)'}`)
- process.exit(1)
- }
- if (!['http:', 'https:'].includes(url.protocol)) {
- console.error(`[pc_nuxt] NUXT_API_SERVER_BASE must be http(s): ${value}`)
- process.exit(1)
- }
- NODE
- }
-
- validate_tls_security() {
- if [ "${NODE_TLS_REJECT_UNAUTHORIZED:-}" = "0" ]; then
- log "Refusing deployment: NODE_TLS_REJECT_UNAUTHORIZED=0 disables TLS certificate verification."
- exit 1
- fi
- }
-
- resolve_branch() {
- if [ -z "$BRANCH" ]; then
- BRANCH="$(git rev-parse --abbrev-ref HEAD)"
- fi
- if [ "$BRANCH" = "HEAD" ]; then
- log "Cannot detect git branch. Please run with BRANCH=main ./restart.sh"
- exit 1
- fi
- }
-
- sync_latest_code() {
- log "Force sync code from origin/$BRANCH"
- git fetch origin "$BRANCH"
- if [ -n "$(git status --porcelain)" ]; then
- log "Discard local working tree changes before deploy"
- git status --short
- fi
- git reset --hard "origin/$BRANCH"
- git clean -fd
- }
-
- install_dependencies() {
- log "Install dependencies"
- pnpm install --frozen-lockfile
- }
-
- build_app() {
- log "Build Nuxt app"
- pnpm run build
-
- if [ ! -f ".output/server/index.mjs" ]; then
- log "Build output missing: .output/server/index.mjs"
- exit 1
- fi
- }
-
- restart_app() {
- log "Reload app with pm2 ecosystem config"
- mkdir -p logs
- APP_NAME="$APP_NAME" pm2 startOrReload ecosystem.config.cjs --env production --update-env
- pm2 save >/dev/null 2>&1 || true
- }
-
- main() {
- require_command git
- require_command node
- require_command pnpm
- require_command pm2
- validate_tls_security
- validate_api_base
- validate_server_api_base
- resolve_branch
-
- log "Deploy start: $APP_NAME"
- log "Node: $(node -v 2>/dev/null || echo 'unknown')"
- log "pnpm: $(pnpm -v)"
- log "pm2: $(pm2 -v)"
- log "API: $NUXT_PUBLIC_API_BASE"
- log "Server API: $NUXT_API_SERVER_BASE"
-
- sync_latest_code
- install_dependencies
- build_app
- restart_app
-
- log "Deploy done: $APP_NAME"
- }
-
- main "$@"
|