aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/static
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-14 23:51:36 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-14 23:51:36 +0200
commite12570f9d1aa2645e6bb223b1417fa0e81957b65 (patch)
treed3eda196ed925dc4fbedcb7671b38bd1f05f552d /packages/meshbay-hub/src/meshbay_hub/static
parentcd2745cecff12e894e0dfa702bff6a90f0e8734e (diff)
downloadmeshbay-e12570f9d1aa2645e6bb223b1417fa0e81957b65.tar.gz
fix(win): a service-mode daemon can be replaced, and the Node page can link one
Two live-reproduced bugs in Windows node start/stop, found sideloading the 0.14.0 build: - node:start's crash-recovery step killed a service-mode daemon with taskkill/CTRL_BREAK, both of which fail with "Access is denied" against a process running under the Scheduled Task's own S4U logon session (a different session from the Electron app's). The daemon it was meant to replace just kept running, unreplaced, and schtasks /run on a task Windows still considered Running was then a silent no-op too. Route through winServiceTaskEnd() (schtasks /end) first, the way nodeServiceStop/ nodeServiceRestart already correctly do. service-mode.ps1 also now starts the task right after registering it -- Register-ScheduledTask's own AtStartup trigger does not run it immediately, so nothing was listening until the next reboot. - The Node page's Start button called node.start() with no arguments, so an unlinked node (a fresh install, or one whose hub-side link was lost) could never link on Start alone -- only create-group-page.js's own call passed {hubUrl, username, token}. Reproduced on a fresh non-service install signed in to the real hub: Start hung for ~105s and failed with "could not link", pointing at a "Link Node" control that lives on Settings, not the Node page (that message is fixed too). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/app.js2
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/node-page.js23
2 files changed, 18 insertions, 7 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/app.js b/packages/meshbay-hub/src/meshbay_hub/static/app.js
index 87c4e33..367774f 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/app.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/app.js
@@ -1042,7 +1042,7 @@ function App() {
.catch(() => {});
}} />`;
} else if (route === '/node' && platform.capabilities.nodeAdmin && hasNodeKey) {
- page = html`<${LazyNodePage} groups=${groups} />`;
+ page = html`<${LazyNodePage} groups=${groups} token=${user.token} username=${user.username} />`;
} else if (route.startsWith('/group/')) {
const groupId = route.slice(7);
const group = groups.find(g => g.id === groupId);
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/node-page.js b/packages/meshbay-hub/src/meshbay_hub/static/node-page.js
index 6dcaa58..0f75edc 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/node-page.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/node-page.js
@@ -4,6 +4,7 @@ import {
import { t } from './i18n.js';
import * as platform from './platform.js';
import { Icon } from './icon.js';
+import { HUB } from './hub-client.js';
// ── Node management (D5) ────────────────────────────────────────────────────
//
@@ -11,7 +12,7 @@ import { Icon } from './icon.js';
// (platform.node.call), not over MNP/WebRTC. The MNP protocol types remain
// for potential future browser-side use.
-function NodeServicePanel({ onChanged }) {
+function NodeServicePanel({ onChanged, token, username }) {
const [info, setInfo] = useState(null);
const [busy, setBusy] = useState('');
const [err, setErr] = useState('');
@@ -77,6 +78,16 @@ function NodeServicePanel({ onChanged }) {
});
}, [act, info]);
+ // The Start button below passes {hubUrl, username, token} to node:start,
+ // same as create-group-page.js's own startNode() -- node:start only links
+ // an unlinked node key to the hub account when given credentials to link
+ // it with (main.js's linkNodeKeyAndAwaitRunning). Without them, a node that
+ // is not linked yet (a fresh install, or one whose hub-side link was lost)
+ // just polls for up to 105s and fails with "could not link", pointing at a
+ // "Link Node" control that lives on Settings, not here. Reproduced live
+ // 2026-09-14: a fresh non-service install's own Start button hung and
+ // failed this way, the exact same account and key that had just linked
+ // fine through the Create Group wizard.
if (!platform.node.service.available) return null;
if (!info || info.supported === false) {
return html`<div class="node-service">
@@ -108,7 +119,7 @@ function NodeServicePanel({ onChanged }) {
${err && html`<div class="error-msg">${err}</div>`}
<div class="node-service-actions">
<button class="btn btn-small btn-secondary" disabled=${!!busy || running}
- onClick=${() => act('start', () => platform.node.start())}>
+ onClick=${() => act('start', () => platform.node.start({ hubUrl: HUB, username, token }))}>
${busy === 'start' ? t('node.service_starting') : t('node.service_start')}</button>
${info.installed && html`
<button class="btn btn-small btn-secondary" disabled=${!!busy || !running}
@@ -171,7 +182,7 @@ async function saveCsv(filename, text) {
URL.revokeObjectURL(url);
}
-export function NodePage({ groups }) {
+export function NodePage({ groups, token, username }) {
const [status, setStatus] = useState('idle');
const [error, setError] = useState('');
const [nodeGroups, setNodeGroups] = useState([]);
@@ -664,14 +675,14 @@ export function NodePage({ groups }) {
if (status === 'idle' || status === 'connecting') {
return html`<div class="page-content">
<h2>${t('node.title')}</h2>
- <${NodeServicePanel} onChanged=${fetchStatus} />
+ <${NodeServicePanel} onChanged=${fetchStatus} token=${token} username=${username} />
<p class="page-message"><span class="spinner"></span>${' '}${t('status.connecting')}</p>
</div>`;
}
if (status === 'error') {
return html`<div class="page-content">
<h2>${t('node.title')}</h2>
- <${NodeServicePanel} onChanged=${fetchStatus} />
+ <${NodeServicePanel} onChanged=${fetchStatus} token=${token} username=${username} />
<p class="error-msg">${error}</p>
<button class="btn btn-primary" onClick=${fetchStatus}>
${t('node.retry')}</button>
@@ -686,7 +697,7 @@ export function NodePage({ groups }) {
onClick=${reloadConfig}>
${t('node.reload')}</button>
</div>
- <${NodeServicePanel} onChanged=${fetchStatus} />
+ <${NodeServicePanel} onChanged=${fetchStatus} token=${token} username=${username} />
${actionMsg && html`<div class="node-message">${actionMsg}</div>`}
${!operatorPaired && html`
<div class="node-pair-banner">