// Single public entrypoint for HF Spaces: local dashboard + reverse proxy to Paperclip. const http = require("http"); const fs = require("fs"); const net = require("net"); const PORT = 7861; const APP_PORT = 3100; const APP_HOST = "127.0.0.1"; const startTime = Date.now(); const INVITE_URL_FILE = "/tmp/invite-url.txt"; const SYNC_STATUS_FILE = "/tmp/sync-status.json"; const CLOUDFLARE_KEEPALIVE_STATUS_FILE = "/tmp/huggingclip-cloudflare-keepalive-status.json"; function parseRequestUrl(url) { try { return new URL(url, "http://localhost"); } catch { return new URL("http://localhost/"); } } function getSyncStatus() { try { if (fs.existsSync(SYNC_STATUS_FILE)) { const raw = fs.readFileSync(SYNC_STATUS_FILE, "utf8"); const parsed = JSON.parse(raw); if (!parsed.status && parsed.db_status) parsed.status = parsed.db_status; if (!parsed.message) { if (parsed.last_error) parsed.message = parsed.last_error; else if (parsed.last_sync_time) parsed.message = `Last sync: ${parsed.last_sync_time}`; } return parsed; } } catch {} if (process.env.HF_TOKEN) { return { status: "configured", message: `Backup is enabled. Waiting for sync window (${process.env.SYNC_INTERVAL || 3600}s).`, }; } return { status: "disabled", message: "HF_TOKEN not set" }; } function getKeepaliveStatus() { try { if (fs.existsSync(CLOUDFLARE_KEEPALIVE_STATUS_FILE)) { return JSON.parse( fs.readFileSync(CLOUDFLARE_KEEPALIVE_STATUS_FILE, "utf8"), ); } } catch {} return null; } async function getPluginStatus(timeoutMs = 1500) { // Try several possible Paperclip API endpoints to list plugins/tools const paths = ["/api/plugins", "/api/tools", "/api/plugins/list"]; for (const p of paths) { try { const result = await new Promise((resolve) => { const req = http.get( { hostname: APP_HOST, port: APP_PORT, path: p, timeout: timeoutMs }, (res) => { let body = ""; res.on("data", (c) => (body += c)); res.on("end", () => resolve({ statusCode: res.statusCode, body })); }, ); req.on("timeout", () => { req.destroy(); resolve(null); }); req.on("error", () => resolve(null)); }); if (!result || !result.body) continue; if (result.statusCode >= 400) continue; try { const parsed = JSON.parse(result.body); let list = []; if (Array.isArray(parsed)) list = parsed; else if (parsed.plugins && Array.isArray(parsed.plugins)) list = parsed.plugins; else if (parsed.tools && Array.isArray(parsed.tools)) list = parsed.tools; else if (parsed.items && Array.isArray(parsed.items)) list = parsed.items; // Normalize list to array of names/ids const names = list.map((it) => typeof it === "string" ? it : it.name || it.id || JSON.stringify(it), ); return { count: names.length, list: names }; } catch (e) { continue; } } catch (e) { continue; } } return null; } function getInviteUrl() { try { if (fs.existsSync(INVITE_URL_FILE)) { return fs.readFileSync(INVITE_URL_FILE, "utf8").trim(); } } catch {} return null; } function probeAppHealth(timeoutMs = 1500) { return new Promise((resolve) => { const request = http.get( { hostname: APP_HOST, port: APP_PORT, path: "/api/health", timeout: timeoutMs, }, (response) => { response.resume(); resolve(response.statusCode >= 200 && response.statusCode < 400); }, ); request.on("timeout", () => { request.destroy(); resolve(false); }); request.on("error", () => resolve(false)); }); } function formatUptime(ms) { const total = Math.floor(ms / 1000); const days = Math.floor(total / 86400); const hours = Math.floor((total % 86400) / 3600); const minutes = Math.floor((total % 3600) / 60); if (days) return `${days}d ${hours}h ${minutes}m`; if (hours) return `${hours}h ${minutes}m`; return `${minutes}m`; } function escapeHtml(value) { return String(value) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } function toneBadge(label, tone = "neutral") { return `${escapeHtml(label)}`; } function renderTile({ title, value, detail = "", tone = "neutral", meta = "", }) { return `
${escapeHtml(title)}
${value}
${detail ? `
${detail}
` : ""} ${meta ? `
${meta}
` : ""}
`; } function renderDashboard(data) { const syncStatus = String(data.sync?.status || "unknown"); const syncTone = ["success", "restored", "synced", "configured"].includes( syncStatus, ) ? "ok" : syncStatus === "disabled" ? "warn" : "neutral"; const backupDetail = data.sync?.message ? escapeHtml(data.sync.message) : "No status yet"; // Show a concise status meta for the Backup tile (last sync time or sync count) const backupMeta = (() => { if (data.sync?.last_sync_time) { return `Last sync: ${escapeHtml(data.sync.last_sync_time)}`; } if (typeof data.sync?.sync_count === "number") { return `Syncs: ${String(data.sync.sync_count)}`; } return ""; })(); const keepaliveConfigured = data.keepalive?.configured === true; const keepaliveStatus = String( data.keepalive?.status || (process.env.CLOUDFLARE_WORKERS_TOKEN ? "pending" : "not configured"), ); const keepAliveTone = keepaliveConfigured ? "ok" : process.env.CLOUDFLARE_WORKERS_TOKEN ? "warn" : "neutral"; const keepAliveDetail = keepaliveConfigured ? `Pinging ${escapeHtml(data.keepalive.targetUrl || "/health")}` : process.env.CLOUDFLARE_WORKERS_TOKEN ? "Worker pending or failed" : "Not configured"; const inviteUrl = getInviteUrl(); const pluginCount = Number(data.plugins?.count || 0); const pluginList = Array.isArray(data.plugins?.list) ? data.plugins.list : []; const tiles = [ renderTile({ title: "Paperclip Core", value: toneBadge( data.appReady ? "Online" : "Booting", data.appReady ? "ok" : "warn", ), detail: `Backend Port ${APP_PORT}`, tone: data.appReady ? "ok" : "warn", }), renderTile({ title: "Database", value: toneBadge("PostgreSQL", "ok"), detail: "Embedded cluster active", tone: "ok", }), renderTile({ title: "Runtime", value: escapeHtml(data.uptimeHuman), detail: `Exposed on port ${PORT}`, tone: "neutral", }), renderTile({ title: "Backup", value: toneBadge(syncStatus.toUpperCase(), syncTone), detail: backupDetail, tone: syncTone, meta: data.sync?.timestamp ? `${backupMeta} | ` : backupMeta, }), renderTile({ title: "Plugins", value: toneBadge( pluginCount ? String(pluginCount) : "0", pluginCount ? "ok" : "neutral", ), detail: pluginCount ? escapeHtml(pluginList.slice(0, 6).join(", ")) : "No plugins loaded", meta: pluginCount > 6 ? `+${pluginCount - 6} more` : "", tone: pluginCount ? "ok" : "neutral", }), renderTile({ title: "Keep Awake", value: toneBadge( keepaliveConfigured ? "CF Cron" : keepaliveStatus.toUpperCase(), keepAliveTone, ), detail: keepAliveDetail, tone: keepAliveTone, }), ].join(""); return ` HuggingClip

HuggingClip

Paperclip Orchestrator Dashboard
${ inviteUrl ? `
Admin Setup Required ${escapeHtml(inviteUrl)}
` : "" } Open Paperclip UI ->
${tiles}
`; } const server = http.createServer(async (req, res) => { const url = parseRequestUrl(req.url); const pathname = url.pathname; if (pathname === "/health") { const appReady = await probeAppHealth(); const plugins = await getPluginStatus(); res.writeHead(appReady ? 200 : 503, { "Content-Type": "application/json" }); return res.end( JSON.stringify({ status: appReady ? "ok" : "booting", uptime: formatUptime(Date.now() - startTime), sync: getSyncStatus(), keepalive: getKeepaliveStatus(), plugins: plugins, }), ); } if (pathname === "/" || pathname === "/dashboard") { const appReady = await probeAppHealth(); const plugins = await getPluginStatus(); res.writeHead(200, { "Content-Type": "text/html" }); return res.end( renderDashboard({ uptimeHuman: formatUptime(Date.now() - startTime), appReady, sync: getSyncStatus(), keepalive: getKeepaliveStatus(), plugins: plugins, }), ); } // Proxy logic to Paperclip (port 3100) const proxyHeaders = { ...req.headers, host: `${APP_HOST}:${APP_PORT}`, "x-forwarded-for": req.socket.remoteAddress, "x-forwarded-host": req.headers.host, "x-forwarded-proto": "https", }; const proxyReq = http.request( { hostname: APP_HOST, port: APP_PORT, path: pathname + url.search, method: req.method, headers: proxyHeaders, }, (proxyRes) => { res.writeHead(proxyRes.statusCode, proxyRes.headers); proxyRes.pipe(res); proxyRes.on("error", () => res.end()); }, ); req.on("error", () => proxyReq.destroy()); res.on("error", () => proxyReq.destroy()); proxyReq.on("error", () => { if (!res.headersSent) { res.writeHead(503, { "Content-Type": "application/json" }); res.end( JSON.stringify({ status: "starting", message: "Paperclip is booting...", }), ); } else { res.end(); } }); req.pipe(proxyReq); }); server.on("upgrade", (req, socket, head) => { const url = parseRequestUrl(req.url); const proxyPath = url.pathname; const proxySocket = net.connect(APP_PORT, APP_HOST, () => { proxySocket.write( `${req.method} ${proxyPath}${url.search} HTTP/${req.httpVersion}\r\n`, ); for (let i = 0; i < req.rawHeaders.length; i += 2) { proxySocket.write(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}\r\n`); } proxySocket.write("\r\n"); if (head && head.length) proxySocket.write(head); proxySocket.pipe(socket).pipe(proxySocket); }); proxySocket.on("error", () => socket.destroy()); }); server.timeout = 0; server.keepAliveTimeout = 65000; server.listen(PORT, "0.0.0.0", () => console.log(`HuggingClip Dashboard on ${PORT} -> Paperclip on ${APP_PORT}`), );