import { useEffect, useState } from "react";
type AppState = "waiting_for_token" | "ready";
/**
* Minimal iframe handshake skeleton for a platform-loaded UI.
*
* 1. UI mounts → posts `{ type: "ready" }` to window.parent.
* 2. Platform replies with `{ type: "auth_token", token, expires_at }`.
* 3. UI uses the token as `Authorization: Bearer ${token}` for any
* backend fetches against `/api/v2/node-apps/{{name}}/api/...`.
*
* The platform refreshes the token by posting another `auth_token` before
* expiry — keep the listener mounted for the lifetime of the app.
*/
export default function App() {
const [state, setState] = useState<AppState>("waiting_for_token");
const [token, setToken] = useState<string | null>(null);
useEffect(() => {
function handleMessage(event: MessageEvent) {
if (event.origin !== window.location.origin) return;
const msg = event.data;
if (!msg || typeof msg !== "object") return;
if (msg.type === "auth_token" && msg.token) {
setToken(msg.token);
setState("ready");
}
}
window.addEventListener("message", handleMessage);
window.parent.postMessage({ type: "ready" }, window.location.origin);
return () => window.removeEventListener("message", handleMessage);
}, []);
return (
<main style={{ fontFamily: "system-ui, sans-serif", padding: 24 }}>
<h1 style={{ fontSize: 18, margin: 0 }}>{"{{name}}"}</h1>
<p style={{ color: "#666", marginTop: 8 }}>
{state === "waiting_for_token"
? "Authorizing…"
: `Authorized (token …${token?.slice(-6) ?? ""})`}
</p>
</main>
);
}