bloby-bot 0.22.10 → 0.22.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/cli.js CHANGED
@@ -714,6 +714,72 @@ function writeVersionFile(version) {
714
714
  try { fs.writeFileSync(path.join(DATA_DIR, 'VERSION'), version); } catch {}
715
715
  }
716
716
 
717
+ /**
718
+ * Poll health endpoint and config.json until the daemon is ready.
719
+ * Advances the stepper through tunnel + verification steps.
720
+ */
721
+ async function waitForDaemonHealth(stepper, config, hasTunnel) {
722
+ const port = config.port || 7400;
723
+ const relayUrl = config.relay?.url || null;
724
+ let tunnelUrl = null;
725
+ let tunnelShown = false;
726
+ let healthOk = false;
727
+
728
+ // Clear any stale tunnelUrl from config so we detect the fresh one
729
+ const oldTunnelUrl = config.tunnelUrl || null;
730
+
731
+ for (let i = 0; i < 120; i++) {
732
+ await new Promise(r => setTimeout(r, 1000));
733
+
734
+ // Check for new tunnel URL in config
735
+ if (hasTunnel && !tunnelShown) {
736
+ try {
737
+ const cfg = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
738
+ if (cfg.tunnelUrl && cfg.tunnelUrl !== oldTunnelUrl) {
739
+ tunnelUrl = cfg.tunnelUrl;
740
+ stepper.advance(); // Connecting tunnel done
741
+ if (relayUrl) {
742
+ stepper.setInfo([
743
+ ` ${c.dim}Waiting for ${c.reset}${c.white}${relayUrl.replace('https://', '')}${c.reset}${c.dim} to become reachable (can take up to 2 min)${c.reset}`,
744
+ ` ${c.dim}In the meanwhile you can access:${c.reset} ${c.blue}${link(tunnelUrl)}${c.reset}`,
745
+ ]);
746
+ }
747
+ tunnelShown = true;
748
+ }
749
+ } catch {}
750
+ }
751
+
752
+ // Check health
753
+ try {
754
+ const res = await fetch(`http://127.0.0.1:${port}/api/health`);
755
+ if (res.ok) {
756
+ healthOk = true;
757
+ break;
758
+ }
759
+ } catch {}
760
+ }
761
+
762
+ // If tunnel never came up, advance past tunnel step anyway
763
+ if (hasTunnel && !tunnelShown) {
764
+ stepper.advance();
765
+ }
766
+
767
+ if (tunnelShown) {
768
+ stepper.setInfo([]);
769
+ }
770
+
771
+ // Advance past "Verifying connection"
772
+ stepper.advance();
773
+
774
+ // Re-read config for final URLs
775
+ try {
776
+ const cfg = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
777
+ if (cfg.tunnelUrl) tunnelUrl = cfg.tunnelUrl;
778
+ } catch {}
779
+
780
+ return { tunnelUrl, relayUrl, healthOk };
781
+ }
782
+
717
783
  // ── Steps ──
718
784
 
719
785
  function createConfig() {
@@ -1289,13 +1355,19 @@ async function update() {
1289
1355
  const selfUpdate = !!process.env.BLOBY_SELF_UPDATE;
1290
1356
  const daemonWasRunning = !selfUpdate && isDaemonInstalled() && isDaemonActive();
1291
1357
 
1358
+ const updateConfig = fs.existsSync(CONFIG_PATH) ? JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8')) : {};
1359
+ const updateTunnelMode = updateConfig.tunnel?.mode ?? (updateConfig.tunnel?.enabled === false ? 'off' : 'quick');
1360
+ const updateHasTunnel = updateTunnelMode !== 'off';
1361
+
1292
1362
  const steps = [
1293
1363
  'Downloading update',
1294
1364
  ...(daemonWasRunning ? ['Stopping daemon'] : []),
1295
1365
  'Updating files',
1296
1366
  'Installing dependencies',
1297
1367
  'Building interface',
1298
- ...(daemonWasRunning ? ['Restarting daemon'] : []),
1368
+ ...(daemonWasRunning
1369
+ ? ['Restarting daemon', ...(updateHasTunnel ? ['Connecting tunnel', 'Verifying connection'] : ['Verifying connection'])]
1370
+ : []),
1299
1371
  ];
1300
1372
 
1301
1373
  const stepper = new Stepper(steps);
@@ -1410,6 +1482,7 @@ async function update() {
1410
1482
  fs.rmSync(tmpDir, { recursive: true, force: true });
1411
1483
 
1412
1484
  // Restart daemon if it was running (skipped during self-update)
1485
+ let updateResult = null;
1413
1486
  if (daemonWasRunning) {
1414
1487
  try {
1415
1488
  if (PLATFORM === 'darwin') {
@@ -1419,7 +1492,10 @@ async function update() {
1419
1492
  execSync(cmd, { stdio: 'ignore' });
1420
1493
  }
1421
1494
  } catch {}
1422
- stepper.advance();
1495
+ stepper.advance(); // Restarting daemon done
1496
+
1497
+ // Wait for daemon to become healthy and tunnel to connect
1498
+ updateResult = await waitForDaemonHealth(stepper, updateConfig, updateHasTunnel);
1423
1499
  }
1424
1500
 
1425
1501
  stepper.finish();
@@ -1442,7 +1518,9 @@ async function update() {
1442
1518
  }
1443
1519
 
1444
1520
  if (daemonWasRunning) {
1445
- if (isDaemonActive()) {
1521
+ if (updateResult && updateResult.tunnelUrl && updateHasTunnel) {
1522
+ finalMessage(updateResult.tunnelUrl, updateResult.relayUrl);
1523
+ } else if (updateResult && updateResult.healthOk) {
1446
1524
  console.log(` ${c.blue}✔${c.reset} Daemon restarted with new version.\n`);
1447
1525
  } else {
1448
1526
  console.log(` ${c.yellow}⚠${c.reset} Daemon may still be starting. Check ${c.pink}bloby daemon status${c.reset}\n`);
@@ -1544,9 +1622,37 @@ async function daemon(sub) {
1544
1622
  console.log(`\n ${c.yellow}⚠${c.reset} Daemon not installed. Run ${c.pink}bloby daemon install${c.reset} first.\n`);
1545
1623
  process.exit(1);
1546
1624
  }
1625
+
1626
+ banner();
1627
+
1628
+ const restartConfig = fs.existsSync(CONFIG_PATH) ? JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8')) : {};
1629
+ const restartTunnelMode = restartConfig.tunnel?.mode ?? (restartConfig.tunnel?.enabled === false ? 'off' : 'quick');
1630
+ const restartHasTunnel = restartTunnelMode !== 'off';
1631
+
1632
+ const restartSteps = [
1633
+ 'Stopping daemon',
1634
+ 'Starting daemon',
1635
+ ...(restartHasTunnel ? ['Connecting tunnel', 'Verifying connection'] : ['Verifying connection']),
1636
+ ];
1637
+ const restartStepper = new Stepper(restartSteps);
1638
+ restartStepper.start();
1639
+
1547
1640
  try { execSync(`launchctl unload "${LAUNCHD_PLIST_PATH}" 2>/dev/null`, { stdio: 'ignore' }); } catch {}
1641
+ restartStepper.advance(); // Stopping daemon done
1642
+
1548
1643
  execSync(`launchctl load "${LAUNCHD_PLIST_PATH}"`, { stdio: 'ignore' });
1549
- console.log(`\n ${c.blue}✔${c.reset} Bloby daemon restarted.\n`);
1644
+ restartStepper.advance(); // Starting daemon done
1645
+
1646
+ const restartResult = await waitForDaemonHealth(restartStepper, restartConfig, restartHasTunnel);
1647
+ restartStepper.finish();
1648
+
1649
+ if (!restartHasTunnel) {
1650
+ privateNetworkMessage(restartConfig.port);
1651
+ } else if (restartResult.tunnelUrl) {
1652
+ finalMessage(restartResult.tunnelUrl, restartResult.relayUrl);
1653
+ } else {
1654
+ console.log(`\n ${c.blue}✔${c.reset} Bloby daemon restarted.\n`);
1655
+ }
1550
1656
  break;
1551
1657
  }
1552
1658
 
@@ -1654,8 +1760,37 @@ async function daemon(sub) {
1654
1760
 
1655
1761
  case 'restart': {
1656
1762
  if (needsSudo()) sudoReExec();
1657
- execSync(`systemctl restart ${SERVICE_NAME}`, { stdio: 'inherit' });
1658
- console.log(`\n ${c.blue}✔${c.reset} Bloby daemon restarted.\n`);
1763
+
1764
+ banner();
1765
+
1766
+ const sysRestartConfig = fs.existsSync(CONFIG_PATH) ? JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8')) : {};
1767
+ const sysRestartTunnelMode = sysRestartConfig.tunnel?.mode ?? (sysRestartConfig.tunnel?.enabled === false ? 'off' : 'quick');
1768
+ const sysRestartHasTunnel = sysRestartTunnelMode !== 'off';
1769
+
1770
+ const sysRestartSteps = [
1771
+ 'Stopping daemon',
1772
+ 'Starting daemon',
1773
+ ...(sysRestartHasTunnel ? ['Connecting tunnel', 'Verifying connection'] : ['Verifying connection']),
1774
+ ];
1775
+ const sysRestartStepper = new Stepper(sysRestartSteps);
1776
+ sysRestartStepper.start();
1777
+
1778
+ execSync(`systemctl stop ${SERVICE_NAME}`, { stdio: 'ignore' });
1779
+ sysRestartStepper.advance(); // Stopping daemon done
1780
+
1781
+ execSync(`systemctl start ${SERVICE_NAME}`, { stdio: 'ignore' });
1782
+ sysRestartStepper.advance(); // Starting daemon done
1783
+
1784
+ const sysRestartResult = await waitForDaemonHealth(sysRestartStepper, sysRestartConfig, sysRestartHasTunnel);
1785
+ sysRestartStepper.finish();
1786
+
1787
+ if (!sysRestartHasTunnel) {
1788
+ privateNetworkMessage(sysRestartConfig.port);
1789
+ } else if (sysRestartResult.tunnelUrl) {
1790
+ finalMessage(sysRestartResult.tunnelUrl, sysRestartResult.relayUrl);
1791
+ } else {
1792
+ console.log(`\n ${c.blue}✔${c.reset} Bloby daemon restarted.\n`);
1793
+ }
1659
1794
  break;
1660
1795
  }
1661
1796