#!/usr/bin/env bash # TOASTSIM — deploy to partly.party/toastsim (games VPS, forum-nginx pattern). # ./scripts/deploy.sh # Build with subpath base → rsync to VPS staging → docker cp into web root → curl verify. set -euo pipefail VPS="humanjing@100.71.119.27" CONTAINER="forum-nginx" REMOTE_WEB_ROOT="/usr/share/nginx/html/toastsim" STAGING="/tmp/toastsim_deploy" REPO="$(cd "$(dirname "$0")/.." && pwd)" echo "[1/6] Building (base=/toastsim/)..." cd "$REPO" ./node_modules/.bin/tsc --noEmit ./node_modules/.bin/vite build --base=/toastsim/ echo "[2/6] Rsync dist → $VPS:$STAGING ..." ssh "$VPS" "rm -rf '$STAGING' && mkdir -p '$STAGING'" rsync -az dist/ "$VPS:$STAGING/" echo "[3/6] Merge into $CONTAINER:$REMOTE_WEB_ROOT ..." # ADDITIVE on purpose — no rm, no gap. The old flow (rm -rf, then docker cp) # had a downtime window, and worse: any browser/CDN holding yesterday's # index.html pointed at hashed bundles the rm had just deleted → the classic # "module script served as text/html" outage. Hashed assets never collide, so # merging keeps every old build's bundles alive for stale HTML while the new # index.html takes over for everyone else. Disk cost is a few MB per deploy; # prune assets/ older than ~30 days by hand if it ever matters. ssh "$VPS" "docker exec '$CONTAINER' mkdir -p '$REMOTE_WEB_ROOT' \ && docker cp '$STAGING/.' '$CONTAINER:$REMOTE_WEB_ROOT/'" echo "[4/6] Rebuild for monsterrobot.games (base=/games/toastsim/)..." # Second live home: https://monsterrobot.games/games/toastsim/ — served by # forum-nginx via the host bind mount, so writing the host path IS the deploy. # It needs its own build: the CF tunnel route for monsterrobot.games answers # /toastsim/* with the lander's HTML fallback, so a /toastsim/-based build # there = "module script served as text/html" (2026-09-01 outage). Rsync is # additive (no --delete) for the same stale-HTML reason as step 3. ./node_modules/.bin/vite build --base=/games/toastsim/ echo "[5/6] Rsync dist → monsterrobot.games host path..." rsync -az dist/ "$VPS:/home/humanjing/monsterrobot.games/games/toastsim/" echo "[6/6] Verify both pages AND the bundles they reference..." ok=1 for url in "https://partly.party/toastsim/" "https://monsterrobot.games/games/toastsim/"; do page=$(curl -s "$url?cb=$(date +%s)") src=$(printf '%s' "$page" | grep -oE 'src="[^"]*\.js"' | sed 's/src="//;s/"//' | head -1) host=$(printf '%s' "$url" | sed -E 's|(https://[^/]+).*|\1|') [ -n "$src" ] || { echo "$url NOT DEPLOYED (no script tag in live index.html)"; ok=0; continue; } ctype=$(curl -so /dev/null -w '%{content_type}' "$host$src") echo "$url → script $src → $ctype" case "$ctype" in application/javascript*|text/javascript*) ;; *) echo "$url NOT DEPLOYED (bundle served as $ctype — stale index or missing asset)"; ok=0 ;; esac done [ "$ok" = 1 ] && echo "done." || exit 1