#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SSH_TUNNEL_TARGET="${SSH_TUNNEL_TARGET:-mevnode_bot}" K8S_NAMESPACE="${K8S_NAMESPACE:-trade-staging}" SSH_FRONTEND_LOCAL_PORT="${SSH_FRONTEND_LOCAL_PORT:-13081}" SSH_HASURA_LOCAL_PORT="${SSH_HASURA_LOCAL_PORT:-18080}" SSH_FRONTEND_REMOTE_HOST="${SSH_FRONTEND_REMOTE_HOST:-127.0.0.1}" SSH_FRONTEND_REMOTE_PORT="${SSH_FRONTEND_REMOTE_PORT:-30081}" SSH_HASURA_REMOTE_PORT="${SSH_HASURA_REMOTE_PORT:-8080}" VITE_DEV_PORT="${VITE_DEV_PORT:-5174}" SSH_PID="" require_cmd() { if ! command -v "$1" >/dev/null 2>&1; then echo "Missing required command: $1" >&2 exit 1 fi } wait_for_listen() { local port="$1" local label="$2" local tries="${3:-80}" local delay="${4:-0.25}" local i for ((i = 0; i < tries; i += 1)); do if ss -ltnH | awk '{print $4}' | grep -Eq "(^|[:])${port}$"; then return 0 fi sleep "${delay}" done echo "Timed out waiting for ${label} on port ${port}" >&2 return 1 } get_cluster_ip() { local service="$1" ssh \ -o BatchMode=yes \ -o StrictHostKeyChecking=accept-new \ -T "${SSH_TUNNEL_TARGET}" \ "kubectl -n ${K8S_NAMESPACE} get svc ${service} -o jsonpath='{.spec.clusterIP}'" } cleanup() { local code=$? trap - EXIT INT TERM if [[ -n "${SSH_PID}" ]] && kill -0 "${SSH_PID}" 2>/dev/null; then kill "${SSH_PID}" 2>/dev/null || true wait "${SSH_PID}" 2>/dev/null || true fi exit "${code}" } trap cleanup EXIT INT TERM require_cmd ssh require_cmd npm require_cmd ss HASURA_CLUSTER_IP="${HASURA_CLUSTER_IP:-$(get_cluster_ip hasura)}" if [[ -z "${HASURA_CLUSTER_IP}" ]]; then echo "Could not resolve ClusterIP for hasura in namespace ${K8S_NAMESPACE}" >&2 exit 1 fi echo "SSH target: ${SSH_TUNNEL_TARGET}" echo "Namespace: ${K8S_NAMESPACE}" echo "hasura ClusterIP: ${HASURA_CLUSTER_IP}" echo "Starting SSH tunnel..." ssh \ -o StrictHostKeyChecking=accept-new \ -o ExitOnForwardFailure=yes \ -o ServerAliveInterval=30 \ -o ServerAliveCountMax=3 \ -N \ -L "${SSH_FRONTEND_LOCAL_PORT}:${SSH_FRONTEND_REMOTE_HOST}:${SSH_FRONTEND_REMOTE_PORT}" \ -L "${SSH_HASURA_LOCAL_PORT}:${HASURA_CLUSTER_IP}:${SSH_HASURA_REMOTE_PORT}" \ "${SSH_TUNNEL_TARGET}" & SSH_PID=$! wait_for_listen "${SSH_FRONTEND_LOCAL_PORT}" "frontend SSH tunnel" wait_for_listen "${SSH_HASURA_LOCAL_PORT}" "Hasura SSH tunnel" echo "Starting Vite on :${VITE_DEV_PORT}..." cd "${SCRIPT_DIR}" export VITE_DEV_PORT export VITE_HASURA_URL="${VITE_HASURA_URL:-/graphql}" export VITE_HASURA_WS_URL="${VITE_HASURA_WS_URL:-ws://127.0.0.1:${SSH_HASURA_LOCAL_PORT}/v1/graphql}" export FRONTEND_PROXY_TARGET="${FRONTEND_PROXY_TARGET:-http://127.0.0.1:${SSH_FRONTEND_LOCAL_PORT}}" export GRAPHQL_PROXY_TARGET="${GRAPHQL_PROXY_TARGET:-http://127.0.0.1:${SSH_HASURA_LOCAL_PORT}}" export GRAPHQL_PROXY_PATH="${GRAPHQL_PROXY_PATH:-/v1/graphql}" echo "Frontend auth proxy: ${FRONTEND_PROXY_TARGET}" echo "GraphQL proxy: ${GRAPHQL_PROXY_TARGET}${GRAPHQL_PROXY_PATH}" echo "Open: http://localhost:${VITE_DEV_PORT}/" exec npm run dev