// Single public entrypoint for HF Spaces: local dashboard + reverse proxy to OpenClaw. const http = require("http"); const https = require("https"); const fs = require("fs"); const net = require("net"); const PORT = 7861; const GATEWAY_PORT = 7860; const GATEWAY_HOST = "127.0.0.1"; const startTime = Date.now(); const LLM_MODEL = process.env.LLM_MODEL || "Not Set"; const TELEGRAM_ENABLED = !!process.env.TELEGRAM_BOT_TOKEN; const WHATSAPP_ENABLED = /^true$/i.test(process.env.WHATSAPP_ENABLED || ""); const WHATSAPP_STATUS_FILE = "/tmp/huggingclaw-wa-status.json"; const HF_BACKUP_ENABLED = !!(process.env.HF_USERNAME && process.env.HF_TOKEN); const SYNC_INTERVAL = process.env.SYNC_INTERVAL || "600"; const DASHBOARD_BASE = "/dashboard"; const DASHBOARD_STATUS_PATH = `${DASHBOARD_BASE}/status`; const DASHBOARD_HEALTH_PATH = `${DASHBOARD_BASE}/health`; const DASHBOARD_UPTIMEROBOT_PATH = `${DASHBOARD_BASE}/uptimerobot/setup`; const DASHBOARD_APP_BASE = `${DASHBOARD_BASE}/app`; const APP_BASE = "/app"; const SPACE_VISIBILITY_TTL_MS = 10 * 60 * 1000; const spaceVisibilityCache = new Map(); function parseRequestUrl(url) { try { return new URL(url, "http://localhost"); } catch { return new URL("http://localhost/"); } } function isDashboardRoute(pathname) { return ( pathname === "/" || pathname === DASHBOARD_BASE || pathname === `${DASHBOARD_BASE}/` ); } function isDashboardAppRoute(pathname) { return ( pathname === DASHBOARD_APP_BASE || pathname.startsWith(`${DASHBOARD_APP_BASE}/`) ); } function isAppRoute(pathname) { return pathname === APP_BASE || pathname.startsWith(`${APP_BASE}/`); } function isLocalRoute(pathname) { return ( pathname === "/health" || pathname === "/status" || pathname === "/uptimerobot/setup" || pathname === DASHBOARD_HEALTH_PATH || pathname === DASHBOARD_STATUS_PATH || pathname === DASHBOARD_UPTIMEROBOT_PATH ); } function mapAppProxyPath(path) { if (path === DASHBOARD_APP_BASE) return APP_BASE; if (path.startsWith(`${DASHBOARD_APP_BASE}/`)) { return `${APP_BASE}${path.slice(DASHBOARD_APP_BASE.length)}`; } if (path === APP_BASE || path.startsWith(`${APP_BASE}/`)) { return path; } return path; } function appendForwarded(existingValue, nextValue) { const cleanNext = nextValue || ""; if (!existingValue) return cleanNext; if (Array.isArray(existingValue)) return `${existingValue.join(", ")}, ${cleanNext}`; return `${existingValue}, ${cleanNext}`; } function buildProxyHeaders(headers, remoteAddress) { return { ...headers, host: headers.host || `${GATEWAY_HOST}:${GATEWAY_PORT}`, "x-forwarded-for": appendForwarded( headers["x-forwarded-for"], remoteAddress, ), "x-forwarded-host": headers["x-forwarded-host"] || headers.host || "", "x-forwarded-proto": headers["x-forwarded-proto"] || "https", }; } function readSyncStatus() { try { if (fs.existsSync("/tmp/sync-status.json")) { return JSON.parse(fs.readFileSync("/tmp/sync-status.json", "utf8")); } } catch {} if (HF_BACKUP_ENABLED) { return { status: "configured", message: `Backup is enabled. Waiting for the next sync window (${SYNC_INTERVAL}s).`, }; } return { status: "unknown", message: "No sync data yet" }; } function normalizeChannelStatus(channel, configured) { return { configured: configured || !!channel, connected: !!(channel && channel.connected), }; } function readGuardianStatus() { if (!WHATSAPP_ENABLED) { return { configured: false, connected: false, pairing: false }; } try { if (fs.existsSync(WHATSAPP_STATUS_FILE)) { const parsed = JSON.parse(fs.readFileSync(WHATSAPP_STATUS_FILE, "utf8")); return { configured: parsed.configured !== false, connected: parsed.connected === true, pairing: parsed.pairing === true, }; } } catch {} return { configured: true, connected: false, pairing: false }; } function decodeJwtPayload(token) { try { const parts = String(token || "").split("."); if (parts.length < 2) return null; const normalized = parts[1].replace(/-/g, "+").replace(/_/g, "/"); const padded = normalized + "=".repeat((4 - (normalized.length % 4)) % 4); return JSON.parse(Buffer.from(padded, "base64").toString("utf8")); } catch { return null; } } function getSpaceRef(parsedUrl) { const signedToken = parsedUrl.searchParams.get("__sign"); if (!signedToken) return null; const payload = decodeJwtPayload(signedToken); const subject = payload && payload.sub; const match = typeof subject === "string" ? subject.match(/^\/spaces\/([^/]+)\/([^/]+)$/) : null; if (!match) return null; return { owner: match[1], repo: match[2] }; } function fetchStatusCode(url) { return new Promise((resolve, reject) => { const req = https.get( url, { headers: { "user-agent": "HuggingClaw/1.0", accept: "application/json", }, }, (res) => { res.resume(); resolve(res.statusCode || 0); }, ); req.on("error", reject); req.setTimeout(5000, () => { req.destroy(new Error("Request timed out")); }); }); } async function resolveSpaceIsPrivate(parsedUrl) { const ref = getSpaceRef(parsedUrl); if (!ref) return false; const cacheKey = `${ref.owner}/${ref.repo}`; const cached = spaceVisibilityCache.get(cacheKey); if (cached && Date.now() - cached.timestamp < SPACE_VISIBILITY_TTL_MS) { return cached.isPrivate; } try { const statusCode = await fetchStatusCode( `https://huggingface.co/api/spaces/${ref.owner}/${ref.repo}`, ); const isPrivate = statusCode === 401 || statusCode === 403 || statusCode === 404; spaceVisibilityCache.set(cacheKey, { isPrivate, timestamp: Date.now() }); return isPrivate; } catch { if (cached) return cached.isPrivate; return false; } } function renderChannelBadge(channel, configuredLabel) { if (channel && channel.connected) { return '
Active
'; } if (channel && channel.configured) { return `
${configuredLabel}
`; } return '
Disabled
'; } function renderSyncBadge(syncData) { let badgeClass = "status-offline"; let pulseHtml = ""; if (syncData.status === "success" || syncData.status === "configured") { badgeClass = "status-online"; pulseHtml = '
'; } else if (syncData.status === "syncing") { badgeClass = "status-syncing"; pulseHtml = '
'; } return `
${pulseHtml}${String(syncData.status || "unknown").toUpperCase()}
`; } function renderDashboard(initialData) { const controlUiHref = `${APP_BASE}/`; const keepAwakeHtml = initialData.spacePrivate ? `
This Space is private. External monitors cannot reliably access private HF health URLs, so keep-awake setup is only available on public Spaces.
` : `
One-time setup for public Spaces. Paste your UptimeRobot Main API key to create the monitor.
`; return ` HuggingClaw Dashboard

🦞 HuggingClaw

Space Dashboard

Model ${initialData.model}
Uptime ${initialData.uptime}
WhatsApp ${renderChannelBadge(initialData.whatsapp, "Ready to pair")}
Telegram ${renderChannelBadge(initialData.telegram, "Configured")}
Open Control UI
Workspace Sync Status
${renderSyncBadge(initialData.sync)}
Last Sync Activity: ${initialData.sync.timestamp || "Never"} ${initialData.sync.message || "Waiting for first sync..."}
Keep Space Awake ${keepAwakeHtml}
`; } function readRequestBody(req) { return new Promise((resolve, reject) => { let body = ""; req.on("data", (chunk) => { body += chunk; if (body.length > 1024 * 64) { reject(new Error("Request too large")); req.destroy(); } }); req.on("end", () => resolve(body)); req.on("error", reject); }); } function postUptimeRobot(path, form) { const body = new URLSearchParams(form).toString(); return new Promise((resolve, reject) => { const request = https.request( { hostname: "api.uptimerobot.com", port: 443, method: "POST", path, headers: { "Content-Type": "application/x-www-form-urlencoded", "Content-Length": Buffer.byteLength(body), }, }, (response) => { let raw = ""; response.setEncoding("utf8"); response.on("data", (chunk) => { raw += chunk; }); response.on("end", () => { try { resolve(JSON.parse(raw)); } catch { reject(new Error("Unexpected response from UptimeRobot")); } }); }, ); request.on("error", reject); request.write(body); request.end(); }); } async function createUptimeRobotMonitor(apiKey, host) { const cleanHost = String(host || "") .replace(/^https?:\/\//, "") .replace(/\/.*$/, ""); if (!cleanHost) { throw new Error("Missing Space host."); } const monitorUrl = `https://${cleanHost}/health`; const existing = await postUptimeRobot("/v2/getMonitors", { api_key: apiKey, format: "json", logs: "0", response_times: "0", response_times_limit: "1", }); const existingMonitor = Array.isArray(existing.monitors) ? existing.monitors.find((monitor) => monitor.url === monitorUrl) : null; if (existingMonitor) { return { created: false, message: `Monitor already exists for ${monitorUrl}`, }; } const created = await postUptimeRobot("/v2/newMonitor", { api_key: apiKey, format: "json", type: "1", friendly_name: `HuggingClaw ${cleanHost}`, url: monitorUrl, interval: "300", }); if (created.stat !== "ok") { const message = created?.error?.message || created?.message || "Failed to create UptimeRobot monitor."; throw new Error(message); } return { created: true, message: `Monitor created for ${monitorUrl}`, }; } function proxyHttp(req, res, proxyPath = req.url, proxyPort = GATEWAY_PORT) { const proxyReq = http.request( { hostname: GATEWAY_HOST, port: proxyPort, method: req.method, path: proxyPath, headers: buildProxyHeaders(req.headers, req.socket.remoteAddress), }, (proxyRes) => { res.writeHead(proxyRes.statusCode || 502, proxyRes.headers); proxyRes.pipe(res); }, ); proxyReq.on("error", (error) => { res.writeHead(502, { "Content-Type": "application/json" }); res.end( JSON.stringify({ status: "error", message: "Gateway unavailable", detail: error.message, }), ); }); req.pipe(proxyReq); } function serializeUpgradeHeaders(req, remoteAddress) { const forwardedHeaders = []; for (let i = 0; i < req.rawHeaders.length; i += 2) { const name = req.rawHeaders[i]; const value = req.rawHeaders[i + 1]; const lower = name.toLowerCase(); if ( lower === "x-forwarded-for" || lower === "x-forwarded-host" || lower === "x-forwarded-proto" ) { continue; } forwardedHeaders.push(`${name}: ${value}`); } forwardedHeaders.push( `X-Forwarded-For: ${appendForwarded(req.headers["x-forwarded-for"], remoteAddress)}`, ); forwardedHeaders.push( `X-Forwarded-Host: ${req.headers["x-forwarded-host"] || req.headers.host || ""}`, ); forwardedHeaders.push( `X-Forwarded-Proto: ${req.headers["x-forwarded-proto"] || "https"}`, ); return forwardedHeaders; } function proxyUpgrade( req, socket, head, proxyPath = req.url, proxyPort = GATEWAY_PORT, ) { const proxySocket = net.connect(proxyPort, GATEWAY_HOST); proxySocket.on("connect", () => { const requestLines = [ `${req.method} ${proxyPath} HTTP/${req.httpVersion}`, ...serializeUpgradeHeaders(req, req.socket.remoteAddress), "", "", ]; proxySocket.write(requestLines.join("\r\n")); if (head && head.length > 0) { proxySocket.write(head); } socket.pipe(proxySocket).pipe(socket); }); proxySocket.on("error", () => { if (socket.writable) { socket.write("HTTP/1.1 502 Bad Gateway\r\nConnection: close\r\n\r\n"); } socket.destroy(); }); socket.on("error", () => { proxySocket.destroy(); }); } const server = http.createServer((req, res) => { const parsedUrl = parseRequestUrl(req.url || "/"); const pathname = parsedUrl.pathname; const uptime = Math.floor((Date.now() - startTime) / 1000); const uptimeHuman = `${Math.floor(uptime / 3600)}h ${Math.floor((uptime % 3600) / 60)}m`; if (pathname === "/health" || pathname === DASHBOARD_HEALTH_PATH) { res.writeHead(200, { "Content-Type": "application/json" }); res.end( JSON.stringify({ status: "ok", uptime, uptimeHuman, timestamp: new Date().toISOString(), }), ); return; } if (pathname === "/status" || pathname === DASHBOARD_STATUS_PATH) { void (async () => { const guardianStatus = readGuardianStatus(); res.writeHead(200, { "Content-Type": "application/json" }); res.end( JSON.stringify({ model: LLM_MODEL, whatsapp: { configured: guardianStatus.configured, connected: guardianStatus.connected, pairing: guardianStatus.pairing, }, telegram: normalizeChannelStatus(null, TELEGRAM_ENABLED), sync: readSyncStatus(), uptime: uptimeHuman, }), ); })(); return; } if ( pathname === "/uptimerobot/setup" || pathname === DASHBOARD_UPTIMEROBOT_PATH ) { if (req.method !== "POST") { res.writeHead(405, { "Content-Type": "application/json" }); res.end(JSON.stringify({ message: "Method not allowed" })); return; } void (async () => { try { const body = await readRequestBody(req); const parsed = JSON.parse(body || "{}"); const apiKey = String(parsed.apiKey || "").trim(); if (!apiKey) { res.writeHead(400, { "Content-Type": "application/json" }); res.end( JSON.stringify({ message: "Paste your UptimeRobot Main API key first.", }), ); return; } const result = await createUptimeRobotMonitor(apiKey, req.headers.host); res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(result)); } catch (error) { res.writeHead(400, { "Content-Type": "application/json" }); res.end( JSON.stringify({ message: error && error.message ? error.message : "Failed to create UptimeRobot monitor.", }), ); } })(); return; } if (isDashboardRoute(pathname)) { void (async () => { const guardianStatus = readGuardianStatus(); const initialData = { model: LLM_MODEL, whatsapp: { configured: guardianStatus.configured, connected: guardianStatus.connected, pairing: guardianStatus.pairing, }, telegram: normalizeChannelStatus(null, TELEGRAM_ENABLED), sync: readSyncStatus(), uptime: uptimeHuman, spacePrivate: await resolveSpaceIsPrivate(parsedUrl), }; res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" }); res.end(renderDashboard(initialData)); })(); return; } if (isDashboardAppRoute(pathname) || isAppRoute(pathname)) { const proxyPath = mapAppProxyPath(pathname) + (parsedUrl.search || ""); proxyHttp(req, res, proxyPath, GATEWAY_PORT); return; } proxyHttp(req, res); }); server.on("upgrade", (req, socket, head) => { const pathname = parseRequestUrl(req.url || "/").pathname; if (isLocalRoute(pathname)) { socket.destroy(); return; } if (isDashboardAppRoute(pathname) || isAppRoute(pathname)) { const parsedUrl = parseRequestUrl(req.url || "/"); const proxyPath = mapAppProxyPath(pathname) + (parsedUrl.search || ""); proxyUpgrade(req, socket, head, proxyPath, GATEWAY_PORT); return; } proxyUpgrade(req, socket, head); }); server.listen(PORT, "0.0.0.0", () => { console.log( `Health server listening on port ${PORT}; proxying gateway traffic to ${GATEWAY_HOST}:${GATEWAY_PORT}`, ); });