aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-08-22 16:40:54 +0200
committerChristophe Besson <cbesson@gmail.com>2026-08-22 16:40:54 +0200
commit9c136a0e37add42f5d0c8675a797969cfe690de0 (patch)
treed5dfd3a7e2289a769dc987f086eec3f475054f85 /packages/meshbay-hub
parent2dbd70484e65ae57e18c323381136077cd00adad (diff)
downloadmeshbay-9c136a0e37add42f5d0c8675a797969cfe690de0.tar.gz
fix: first-run wizard reliability and node startup performance
Node daemon no longer blocks startup on slow directory scans — initial indexing runs in the background so the node reaches "running" immediately after transports are up. Fixes the wizard failing to detect the node when large USB/NAS roots take minutes to scan. Also: wizard key-linking deadlock resolved (main.js links during poll), invite form stays in DOM during reconnects (disabled instead of destroyed), pairing code bridges to renderer, and firewall docs for LAN casting added. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-hub')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/app.js49
1 files changed, 25 insertions, 24 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/app.js b/packages/meshbay-hub/src/meshbay_hub/static/app.js
index 595674d..5c2bada 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/app.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/app.js
@@ -1201,8 +1201,7 @@ function CreateGroupWizard({ token, username, onCreated }) {
setNodeStarting(true);
setError('');
try {
- const result = await platform.node.start({ hubUrl: HUB, username });
- await linkNodeKey(result.pk_node_ed25519);
+ const result = await platform.node.start({ hubUrl: HUB, username, token });
setNodeStatus({ detected: true, ...result });
setNodeStarting(false);
setStep(1);
@@ -1299,6 +1298,7 @@ function CreateGroupWizard({ token, username, onCreated }) {
const pairResult = await platform.node.call('POST', '/api/operator/pair');
if (pairResult && pairResult.code) {
await platform.node.setPairingCode(pairResult.code);
+ _pendingJoinCode = pairResult.code;
}
update('done');
@@ -2977,37 +2977,38 @@ function GroupSettingsPanel({ groupId, group, token, transportRef, gekRef,
${error && html`<div class="error-msg" style="margin-bottom:12px">${error}</div>`}
${/* Inviting needs the node: it is the node that wraps the group key and
- issues the code, not the hub. Public groups admit anyone — no invite. */
+ issues the code, not the hub. Public groups admit anyone — no invite.
+ The form stays in the DOM so a brief reconnect does not destroy the
+ input the user is typing into — controls are disabled instead. */
isAdmin && group?.join_policy !== 'open' && html`
<div class="settings-section">
<h3 class="settings-heading">${t('members.invite_title')}</h3>
- ${!connected && html`
+ ${!connected ? html`
<p class="settings-hint">${t('group.offline_title')}</p>
- `}
- ${connected && !operatorPaired && html`
+ ` : !operatorPaired ? html`
<p class="settings-hint">
${isNodeAdmin ? t('members.invite_needs_pairing')
: t('members.invite_ask_operator')}
</p>
- `}
- ${connected && operatorPaired && html`
- <form onSubmit=${doInvite}>
- ${inviteCode && html`
- <div class="success-msg" style="margin-bottom:8px">
- <p>${t('members.invite_code_ready', { user: inviteCode.username })}</p>
- <p class="code-display">${inviteCode.code}</p>
- <p>${t('members.invite_code_hint')}</p>
- </div>
- `}
- <div class="form-row">
- <input type="text" placeholder="${t('members.username_placeholder')}"
- value=${inviteUser} onInput=${e => setInviteUser(e.target.value)} required />
- <button class="admin-btn" type="submit" disabled=${inviting}>
- ${inviting ? '...' : t('members.invite_btn')}
- </button>
+ ` : ''}
+ <form onSubmit=${doInvite}>
+ ${inviteCode && html`
+ <div class="success-msg" style="margin-bottom:8px">
+ <p>${t('members.invite_code_ready', { user: inviteCode.username })}</p>
+ <p class="code-display">${inviteCode.code}</p>
+ <p>${t('members.invite_code_hint')}</p>
</div>
- </form>
- `}
+ `}
+ <div class="form-row">
+ <input type="text" placeholder="${t('members.username_placeholder')}"
+ value=${inviteUser} onInput=${e => setInviteUser(e.target.value)}
+ disabled=${!connected || !operatorPaired} required />
+ <button class="admin-btn" type="submit"
+ disabled=${inviting || !connected || !operatorPaired}>
+ ${inviting ? '...' : t('members.invite_btn')}
+ </button>
+ </div>
+ </form>
</div>
`}