diff --git a/mint-tmp.ts b/mint-tmp.ts new file mode 100644 index 00000000..6fbcadd0 --- /dev/null +++ b/mint-tmp.ts @@ -0,0 +1,7 @@ +import { sign } from './src/servers/jwt'; +import { getOwnerUser } from 'officerdb'; +const u = await getOwnerUser(); +if (!u) { console.error('no owner'); process.exit(1); } +const token = await sign({ id: u.id, email: u.email, name: u.name, username: u.username, role: u.role }); +await Bun.write('/tmp/.mstoken', token); +console.log('minted for owner id', u.id, 'role', u.role, '(written to file, not printed)'); diff --git a/src/workspaces/officerdev/src/apps/Minesweeper/MinesweeperPanel.tsx b/src/workspaces/officerdev/src/apps/Minesweeper/MinesweeperPanel.tsx index 195cc69f..7f0cba12 100644 --- a/src/workspaces/officerdev/src/apps/Minesweeper/MinesweeperPanel.tsx +++ b/src/workspaces/officerdev/src/apps/Minesweeper/MinesweeperPanel.tsx @@ -17,7 +17,14 @@ const VISIBLE = { width: 164, height: 226 }; const BUTTON_MASK: Record = { 0: 1, 1: 2, 2: 4 }; export const MinesweeperPanel = () => { + // useClient() rebuilds its verbs on EVERY render, so putting one in a dependency list gives that + // list a new identity every render. Held in a ref instead — the same fix the Jellyfin player needed + // after its playback reports silently stopped for days. Getting this wrong here meant `refresh` was + // unstable, its mount effect re-ran every render, and each run set state and caused another render: + // an endless fetch loop that starved the socket and left the panel saying "connecting…" forever. const client = useClient(); + const clientRef = useRef(client); + clientRef.current = client; const canvasRef = useRef(null); const offscreenRef = useRef(null); const rfbRef = useRef(null); @@ -38,11 +45,11 @@ export const MinesweeperPanel = () => { const refresh = useCallback(async () => { try { - adopt(await client.get("/minesweeper/status")); + adopt(await clientRef.current.get("/minesweeper/status")); } catch { setError("Could not reach the server."); } - }, [client, adopt]); + }, [adopt]); useEffect(() => { void refresh(); @@ -52,7 +59,7 @@ export const MinesweeperPanel = () => { setBusy(true); setError(null); try { - adopt(await client.post("/minesweeper/start", {})); + adopt(await clientRef.current.post("/minesweeper/start", {})); } catch { setError("The session would not start. Is wine-minesweeper installed on the server?"); } finally { @@ -131,7 +138,7 @@ export const MinesweeperPanel = () => { if (!connected) return; const timer = setInterval(async () => { try { - const next = await client.get("/minesweeper/status"); + const next = await clientRef.current.get("/minesweeper/status"); if (!next.window) return; const { width, height } = next.window; if (width !== geometryRef.current.width || height !== geometryRef.current.height) { @@ -143,7 +150,7 @@ export const MinesweeperPanel = () => { } }, 4000); return () => clearInterval(timer); - }, [connected, client, present]); + }, [connected, present]); const toFramebuffer = (ev: React.MouseEvent) => { const rect = ev.currentTarget.getBoundingClientRect();