// useSwarmName — the swarm's configured display name from `GET /api/swarm`, // or `null` until it arrives, when none is configured, or when the fetch // fails. The label is cosmetic, so a failure is swallowed rather than shown: // callers fall back to their own default, as an operator who never set a // name sees. One request per page load, shared by every caller, because the // header and the start page both ask for it and the name does not change // within a visit. import { useEffect, useState } from "preact/hooks"; let pending: Promise | null = null; function fetchSwarmName(): Promise { if (pending === null) { pending = (async () => { const r = await fetch("/api/swarm"); if (!r.ok) return null; const data = (await r.json()) as { name: string | null }; return data.name || null; })().catch(() => null); } return pending; } export function useSwarmName(): string | null { const [name, setName] = useState(null); useEffect(() => { let cancelled = false; void fetchSwarmName().then((n) => { if (!cancelled && n !== null) setName(n); }); return () => { cancelled = true; }; }, []); return name; }