aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-27 22:21:07 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-27 22:21:07 +0200
commitc7899e2218af26f3bab6a157c70acf5eb7871da6 (patch)
tree5ed08cfbf26cdd8d9dbf6ce1159fc259d611df2d /packages/meshbay-hub/src
parent7422a777297347dc83e6c5b2e89c1a6fa99a36b0 (diff)
downloadmeshbay-c7899e2218af26f3bab6a157c70acf5eb7871da6.tar.gz
fix(hub): the sidebar's Node section follows the node link
Reported on a real install: after the first click on Create group, the Node section (Node, Create group) disappeared from the sidebar until a reload, although the group was created and the node ran. hasNodeKey was read once per session change and never again, so a node the wizard linked stayed out of the sidebar; and that read swallowed its errors, so a session blip (a refused renewal, then the desktop app's silent device sign-in) followed by one failed request hid the section for good. The wizard now tells the app when it has linked or started a node, the app asks again then and after a group is created, and a failed read is retried -- never applied to a session that has changed meanwhile. The wizard also starts the node on its own for a node in waiting_for_hub. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-hub/src')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/app.js33
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/create-group-page.js10
2 files changed, 35 insertions, 8 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/app.js b/packages/meshbay-hub/src/meshbay_hub/static/app.js
index 6b20a63..3101be7 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/app.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/app.js
@@ -924,8 +924,31 @@ function App() {
.catch(() => {});
}, [user, notifDisabled]);
+ // Whether this account has a node linked, which is what shows the sidebar's
+ // Node section. Asked again whenever a node may just have been linked (the
+ // Create Group wizard), not only when the session changes -- the section
+ // stayed hidden until a reload after the first group -- and retried rather
+ // than left false by one failed request after a session blip.
+ const nodeKeyAskedForRef = useRef(null);
+ const refreshNodeKey = useCallback(() => {
+ nodeKeyAskedForRef.current = user;
+ if (!user || !platform.capabilities.nodeAdmin) return;
+ // A late answer, or a retry, must not land on a session that has changed.
+ const current = () => nodeKeyAskedForRef.current === user;
+ const ask = (attempt) => hubFetch(`/v1/users/${user.username}/pubkeys`, { token: user.token })
+ .then(data => { if (current()) setHasNodeKey(Boolean(data.pk_node_ed25519)); })
+ .catch(() => {
+ if (attempt < 3 && current()) setTimeout(() => ask(attempt + 1), 2000 * attempt);
+ });
+ ask(1);
+ }, [user]);
+
useEffect(() => {
- if (!user) { setGroups([]); setNotifications([]); setUnreadCount(0); setHasNodeKey(false); return; }
+ if (!user) {
+ nodeKeyAskedForRef.current = null;
+ setGroups([]); setNotifications([]); setUnreadCount(0); setHasNodeKey(false);
+ return;
+ }
hubFetch('/v1/groups/mine', { token: user.token })
.then(data => setGroups(data.groups || []))
.catch(() => setGroups([]));
@@ -935,11 +958,7 @@ function App() {
if (prefs.notifications_disabled === 'true') setNotifDisabled(true);
})
.catch(() => {});
- if (platform.capabilities.nodeAdmin) {
- hubFetch(`/v1/users/${user.username}/pubkeys`, { token: user.token })
- .then(data => setHasNodeKey(Boolean(data.pk_node_ed25519)))
- .catch(() => {});
- }
+ refreshNodeKey();
fetchNotifications();
}, [user]);
@@ -1176,10 +1195,12 @@ function App() {
} else if (route === '/create-group') {
page = html`<${LazyCreateGroupPage} token=${user.token} username=${user.username}
allowPublicGroups=${allowPublicGroups}
+ onNodeLinked=${refreshNodeKey}
onCreated=${() => {
hubFetch('/v1/groups/mine', { token: user.token })
.then(data => setGroups(data.groups || []))
.catch(() => {});
+ refreshNodeKey();
}} />`;
} else if (route === '/node' && platform.capabilities.nodeAdmin && hasNodeKey) {
page = html`<${LazyNodePage} groups=${groups} token=${user.token} username=${user.username} />`;
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/create-group-page.js b/packages/meshbay-hub/src/meshbay_hub/static/create-group-page.js
index 85fe53c..7556010 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/create-group-page.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/create-group-page.js
@@ -124,7 +124,7 @@ function CreateGroupFormSimple({ token, onCreated, allowPublicGroups = true }) {
`;
}
-function CreateGroupWizard({ token, username, onCreated, allowPublicGroups = true }) {
+function CreateGroupWizard({ token, username, onCreated, onNodeLinked, allowPublicGroups = true }) {
const [step, setStep] = useState(0);
const [nodeStatus, setNodeStatus] = useState(null);
const [nodeStarting, setNodeStarting] = useState(false);
@@ -151,7 +151,10 @@ function CreateGroupWizard({ token, username, onCreated, allowPublicGroups = tru
await hubFetch('/v1/users/me/node_key', {
method: 'PUT', token, body: { pk_node_ed25519: pk },
});
- }, [token]);
+ // The sidebar's Node section depends on this link; it only re-read it at
+ // sign-in, so the first node set up here stayed out of it until a reload.
+ if (onNodeLinked) onNodeLinked();
+ }, [token, onNodeLinked]);
const detectNode = useCallback(async () => {
setNodeStatus(null);
@@ -177,6 +180,8 @@ function CreateGroupWizard({ token, username, onCreated, allowPublicGroups = tru
setError('');
try {
const result = await platform.node.start({ hubUrl: HUB, username, token });
+ // node.start links the key from the main process, out of this page's sight.
+ if (onNodeLinked) onNodeLinked();
setNodeStatus({ detected: true, ...result });
setNodeStarting(false);
setStep(1);
@@ -337,6 +342,7 @@ function CreateGroupWizard({ token, username, onCreated, allowPublicGroups = tru
&& !provisionAttempted.current
&& (nodeStatus.status === 'waiting_for_account'
|| nodeStatus.status === 'waiting_for_node_key'
+ || nodeStatus.status === 'waiting_for_hub'
|| nodeStatus.status === 'starting')) {
provisionAttempted.current = true;
startNode();