(function () { "use strict"; const SDK = window.__HERMES_PLUGIN_SDK__; const { React } = SDK; const { useState, useEffect, useCallback } = SDK.hooks; const { Card, CardHeader, CardTitle, CardContent, Button } = SDK.components; async function safeFetchJSON(path, opts) { const res = await fetch(path, opts || {}); const text = await res.text(); try { return JSON.parse(text); } catch (_) { throw new Error("Server returned non-JSON (status " + res.status + "): " + text.slice(0,120)); } } function TTYDPage() { const [link, setLink] = useState(null); const [port, setPort] = useState(null); const [status, setStatus] = useState("idle"); const [error, setError] = useState(null); const start = useCallback(async function () { setStatus("loading"); setError(null); try { var res = await safeFetchJSON("/api/plugins/sshx-link/status"); if (res.status === "installing") { setStatus("installing"); return; } if (res.status === "running" && res.link) { setLink(res.link); setPort(res.port); setStatus("running"); return; } res = await safeFetchJSON("/api/plugins/sshx-link/start"); if (res.link) { setLink(res.link); setPort(res.port || null); setStatus("running"); } else { setError(res.message || "No link returned"); setStatus("error"); } } catch (err) { setError(err.message || "Failed to start ttyd"); setStatus("error"); } }, []); const stop = useCallback(async function () { try { await safeFetchJSON("/api/plugins/sshx-link/stop", { method: "POST" }); setLink(null); setPort(null); setStatus("idle"); } catch (err) { setError(err.message); } }, []); const checkStatus = useCallback(async function () { try { const res = await safeFetchJSON("/api/plugins/sshx-link/status"); if (res.status === "running" && res.link) { setLink(res.link); setPort(res.port || null); setStatus("running"); } else if (res.status === "installing") { setStatus("installing"); } else if (res.status === "stopped") { if (status === "running") { setLink(null); setStatus("idle"); } } } catch (_) {} }, [status]); useEffect(function () { checkStatus(); }, [checkStatus]); useEffect(function () { if (status !== "installing") return; var timer = setInterval(function () { checkStatus(); }, 2000); return function () { clearInterval(timer); }; }, [status, checkStatus]); if (status === "installing") { return React.createElement(Card, null, React.createElement(CardHeader, null, React.createElement(CardTitle, null, "TTYD Shared Terminal") ), React.createElement(CardContent, null, React.createElement("p", { className: "text-sm text-yellow-500", style: { fontWeight: 600 } }, "Installing ttyd (auto arch detect)..."), React.createElement("p", { className: "text-xs text-muted-foreground", style: { marginTop: "0.5rem" } }, "Downloading binary for your arch, no restart needed.") ) ); } if (status === "running" && link) { return React.createElement(Card, null, React.createElement(CardHeader, null, React.createElement(CardTitle, null, "TTYD Shared Terminal"), React.createElement("p", { className: "text-xs text-green-500", style: { fontWeight: 600 } }, "● Running - No dashboard restart needed") ), React.createElement(CardContent, null, React.createElement("a", { href: link, target: "_blank", rel: "noopener noreferrer", style: { color: "#60a5fa", fontSize: "1rem", wordBreak: "break-all", textDecoration: "underline", display: "block", marginBottom: "0.75rem" } }, link), React.createElement("div", { style: { display: "flex", gap: "0.5rem", marginBottom: "1rem" } }, React.createElement(Button, { onClick: function() { navigator.clipboard && navigator.clipboard.writeText(link); }, variant: "outline", size: "sm" }, "Copy Link"), React.createElement(Button, { onClick: stop, variant: "destructive", size: "sm" }, "Stop") ), React.createElement("div", { style: { border: "1px solid #333", borderRadius: "8px", overflow: "hidden", height: "500px", background: "#000" } }, React.createElement("iframe", { src: link, style: { width: "100%", height: "100%", border: "0" }, title: "TTYD Terminal" }) ), React.createElement("p", { className: "text-xs text-muted-foreground", style: { marginTop: "0.5rem" } }, "Terminal embedded above. Open in new tab if iframe blocked by CSP." ) ) ); } return React.createElement(Card, null, React.createElement(CardHeader, null, React.createElement(CardTitle, null, "TTYD Shared Terminal"), React.createElement("p", { className: "text-xs text-muted-foreground" }, "Auto arch detection, no restart required") ), React.createElement(CardContent, null, React.createElement("p", { className: "text-sm text-muted-foreground", style: { marginBottom: "1rem" } }, "Start a shared terminal via ttyd. Works offline, no dependency on sshx.io."), error && React.createElement("p", { className: "text-sm text-red-500", style: { marginBottom: "1rem", whiteSpace: "pre-wrap" } }, "Error: " + error), React.createElement(Button, { onClick: start, disabled: status === "loading" }, status === "loading" ? "Starting ttyd..." : "Start TTYD") ) ); } window.__HERMES_PLUGINS__.register("sshx-link", TTYDPage); })();