#!/usr/bin/env bash # ============================================================ # SVGarden — https://www.svgarden.dev # Author : Simon-Pierre Boucher # Contact: contact@spboucher.ai # File : scripts/deploy.sh # Desc : Deploy to node M3U96b — sync/pull, npm ci, build, pm2, health checks # ============================================================ set -euo pipefail NODE="${SVGARDEN_NODE:-M3U96b}" APP_DIR="~/apps/svgarden" LOCAL_URL="http://127.0.0.1:4321" PUBLIC_URL="https://www.svgarden.dev" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_DIR="$(dirname "$SCRIPT_DIR")" step() { printf '\n\033[1;35m▸ %s\033[0m\n' "$*"; } # 1. Get the latest code onto the node. # With a git remote configured on the node we `git pull` (per CLAUDE.md §9); # until one exists we rsync from this working copy instead. if ssh "$NODE" "cd $APP_DIR 2>/dev/null && git remote get-url origin >/dev/null 2>&1"; then step "git pull on $NODE" ssh "$NODE" "cd $APP_DIR && git pull --ff-only" else step "rsync source → $NODE:$APP_DIR (no git remote yet)" ssh "$NODE" "mkdir -p $APP_DIR" rsync -az --delete \ --exclude node_modules --exclude dist --exclude .git \ --exclude '.env*' --exclude ngrok.yml \ "$REPO_DIR/" "$NODE:$APP_DIR/" fi # 2. Install exact deps + build (validation runs inside `npm run build`). step "npm ci + npm run build on $NODE" ssh "$NODE" "export PATH=/opt/homebrew/bin:\$PATH; cd $APP_DIR && npm ci --no-audit --no-fund && npm run build" # 3. (Re)start server + tunnel under pm2. step "pm2 startOrRestart" ssh "$NODE" "export PATH=/opt/homebrew/bin:\$PATH; cd $APP_DIR && pm2 startOrRestart ecosystem.config.cjs && pm2 save" # 4. Health checks. step "health check $LOCAL_URL (on $NODE)" sleep 3 ssh "$NODE" "curl -fsS -o /dev/null -w 'local %{http_code} %{time_total}s\n' $LOCAL_URL/healthz && curl -fsS $LOCAL_URL/healthz && echo" step "health check $PUBLIC_URL" if curl -fsS -o /dev/null -m 20 -w 'public %{http_code} %{time_total}s\n' "$PUBLIC_URL/healthz"; then curl -fsS -m 20 "$PUBLIC_URL/healthz" && echo else cat <<'EOF' ⚠ Public URL unreachable. The local server is up; the tunnel is not. Check on the node: pm2 logs svgarden-tunnel --lines 30 Likely causes: • www.svgarden.dev not reserved as a custom domain in the ngrok dashboard • DNS CNAME for www.svgarden.dev not pointed at ngrok yet • ngrok agent not authenticated (`ngrok config add-authtoken `) EOF exit 1 fi step "status summary" ssh "$NODE" "export PATH=/opt/homebrew/bin:\$PATH; pm2 ls | grep -E 'svgarden|name' || true" echo "✔ SVGarden deployed — $PUBLIC_URL"