diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-10-07 21:25:47 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-10-07 22:22:51 +0200 |
| commit | e833fe1bfc8eb6f66cc5dc53997cc4158bab583f (patch) | |
| tree | 6874dfd09cb210eaf61e4f5761d0bad23c9cd0a3 /packages/meshbay-hub/src/meshbay_hub/static/app.js | |
| parent | 92e25ffcc5edf5d1a9996bfb921b5a95b826134b (diff) | |
| download | meshbay-e833fe1bfc8eb6f66cc5dc53997cc4158bab583f.tar.gz | |
fix: set the Windows node up at sign-in, and stop it for real
Found by the first Windows beta tester, then reproduced on a clean install.
After a service-mode install nothing set the node up for the account that
signed in: the boot task started a node that quit ("hub.username not set"),
and the sidebar showed Node / Create group only once the hub held a node key.
The only way to the wizard that provisions was the home page's welcome card,
which an account already in a group never sees. The way out was
`meshbay-node init` and the key pasted on the profile page -- which is also
what PACKAGING-GUIDE.md told people to do.
- main.js `node:ensure`, called by app.js at sign-in: provisions, starts and
links the node this build ships (Windows, bundled node only). A node set up
for another account, or an account linked to another node, is left alone.
node:start waits for it, so the two never race.
- The sidebar shows the Node section when a node exists on this machine.
- The Node page's status is the node's: its control API and the process
list, not the service task's state (a node started from a terminal ran
while the page said Stopped). Stop says Stopped only once no
meshbay-node.exe is left, and stays offered for a process that answers
nothing.
- CLI stop kills the pid that answered when a graceful stop does not finish,
and fails with the reason when a node process is still there.
- The daemon ends its process 3s after _shutdown(): Python's exit waited for a
busy indexer thread, with the control API already closed. Armed by main()
only, never by a daemon run inside a test.
- node.toml is read as utf-8-sig (PowerShell 5.1 writes a BOM), and a config
that cannot be read is logged instead of dying silently in service mode.
- "Pair this browser" queues the code for the next group of this node to
open instead of saying "Paired successfully"; no banner before a group.
- test_e2e_windows_app.py (opt-in, MESHBAY_WIN_E2E=1) drives the installed
app against a throwaway hub: fresh account to linked node, Stop, Start,
Restart, checked against the real processes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/app.js')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/static/app.js | 30 |
1 files changed, 26 insertions, 4 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/app.js b/packages/meshbay-hub/src/meshbay_hub/static/app.js index c1913c0..b9466d0 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/app.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/app.js @@ -429,7 +429,7 @@ function Nav({ user, theme, onThemeChange, onLogout, onMenuToggle, unreadCount, // ── Sidebar ────────────────────────────────────────────────────────────────── -function Sidebar({ groups, presence, indexProgressPct, route, menuOpen, role, hasNodeKey, +function Sidebar({ groups, presence, indexProgressPct, route, menuOpen, role, showNode, allowPublicGroups = true }) { const isStaff = role === 'moderator' || role === 'admin'; return html` @@ -449,7 +449,7 @@ function Sidebar({ groups, presence, indexProgressPct, route, menuOpen, role, ha <a class="sidebar-item ${route === '/search' ? 'active' : ''}" href="#/search"><${Icon} name="search" /> ${t('sidebar.search')}</a> </div> - ${platform.capabilities.nodeAdmin && hasNodeKey && html` + ${platform.capabilities.nodeAdmin && showNode && html` <div class="sidebar-section"> <div class="sidebar-heading">${t('sidebar.node')}</div> <a class="sidebar-item ${route === '/node' ? 'active' : ''}" @@ -781,6 +781,9 @@ function App() { const [notifDisabled, setNotifDisabled] = useState(false); const [userPrefs, setUserPrefs] = useState({}); const [hasNodeKey, setHasNodeKey] = useState(false); + // A node on this machine, linked to the account or not: the Node section is + // where it is looked after, so it cannot wait for a link to show up. + const [localNode, setLocalNode] = useState(false); // Instance policy, fetched once, unauthenticated. `null` until it answers; // treat unknown as "allowed" so a slow hub never blocks a legitimate private // group — the hub refuses a public one server-side regardless. @@ -1041,6 +1044,25 @@ function App() { fetchNotifications(); }, [user]); + // The node this application ships, set up, started and linked for whoever + // signs in (main.js `ensureNode`): installing it is all it should take. + // Keyed on the account, not the session object -- the token rotates, and a + // renewal is not a sign-in. + const signedInAs = user ? user.username : null; + useEffect(() => { + setLocalNode(false); + if (!signedInAs || !platform.capabilities.nodeAdmin || !platform.node.available) return; + let cancelled = false; + platform.node.installed() + .then((r) => { if (!cancelled) setLocalNode(Boolean(r && r.installed)); }) + .catch(() => {}); + const live = userRef.current; + platform.node.ensure({ username: live.username, token: live.token }) + .then(() => { if (!cancelled) refreshNodeKey(); }) + .catch(() => {}); + return () => { cancelled = true; }; + }, [signedInAs]); + // After an invitation is accepted: the group is ours now, and only the hub // knows its row the way `/mine` answers it. const reloadGroups = useCallback(() => { @@ -1316,7 +1338,7 @@ function App() { .catch(() => {}); refreshNodeKey(); }} />`; - } else if (route === '/node' && platform.capabilities.nodeAdmin && hasNodeKey) { + } else if (route === '/node' && platform.capabilities.nodeAdmin && (hasNodeKey || localNode)) { page = html`<${LazyNodePage} groups=${groups} token=${user.token} username=${user.username} />`; } else if (groupId) { page = html`<${GroupPage} @@ -1380,7 +1402,7 @@ function App() { menuOpen=${menuOpen} role=${user.role} allowPublicGroups=${allowPublicGroups} - hasNodeKey=${hasNodeKey} />`} + showNode=${hasNodeKey || localNode} />`} ${menuOpen && html`<div class="overlay visible" onClick=${() => setMenuOpen(false)} />`} <main class="main"> |