Skip to content

Commit 4e2de71

Browse files
committed
feat(tunnel): add findDevtunnel function and improve error handling for tunnel mode
1 parent 910eac3 commit 4e2de71

2 files changed

Lines changed: 44 additions & 15 deletions

File tree

src/server.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const { createAuth } = require('./auth');
1212
const { SessionManager } = require('./sessions');
1313
const { setupRoutes, cleanupUploadedFiles } = require('./routes');
1414
const { setupWebSocket } = require('./websocket');
15-
const { startTunnel, cleanupTunnel } = require('./tunnel');
15+
const { startTunnel, cleanupTunnel, findDevtunnel } = require('./tunnel');
1616

1717
// --- Helpers ---
1818
function getLocalIP() {
@@ -75,6 +75,29 @@ function createTermBeamServer(overrides = {}) {
7575
}
7676

7777
function start() {
78+
// Fail early if tunnel mode is on but devtunnel CLI is not installed
79+
if (config.useTunnel && !findDevtunnel()) {
80+
log.error('❌ devtunnel CLI is not installed.');
81+
log.error('');
82+
log.error(' TermBeam uses tunnels by default for remote access.');
83+
log.error(' Install the Azure Dev Tunnels CLI, or use --no-tunnel for LAN-only mode.');
84+
log.error('');
85+
log.error(' Install it:');
86+
log.error(' Windows: winget install Microsoft.devtunnel');
87+
log.error(
88+
' or: Invoke-WebRequest -Uri https://aka.ms/TunnelsCliDownload/win-x64 -OutFile devtunnel.exe',
89+
);
90+
log.error(' macOS: brew install --cask devtunnel');
91+
log.error(' Linux: curl -sL https://aka.ms/DevTunnelCliInstall | bash');
92+
log.error('');
93+
log.error(' Then restart your terminal and try again.');
94+
log.error(
95+
' Docs: https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/get-started',
96+
);
97+
log.error('');
98+
process.exit(1);
99+
}
100+
78101
return new Promise((resolve) => {
79102
server.listen(config.port, config.host, async () => {
80103
const ip = getLocalIP();

src/tunnel.js

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ async function startTunnel(port, options = {}) {
8989
if (!found) {
9090
log.error('❌ devtunnel CLI is not installed.');
9191
log.error('');
92-
log.error(' The --tunnel flag requires the Azure Dev Tunnels CLI.');
92+
log.error(' TermBeam uses tunnels by default for remote access.');
93+
log.error(' Install the Azure Dev Tunnels CLI, or use --no-tunnel for LAN-only mode.');
9394
log.error('');
9495
log.error(' Install it:');
9596
log.error(' Windows: winget install Microsoft.devtunnel');
@@ -120,19 +121,24 @@ async function startTunnel(port, options = {}) {
120121
} catch {}
121122

122123
if (!loggedIn) {
123-
log.info('devtunnel not logged in, launching login...');
124-
log.info('A browser window will open for authentication.');
124+
log.info('devtunnel not logged in, launching browser login (30s timeout)...');
125125
try {
126-
execFileSync(devtunnelCmd, ['user', 'login'], { stdio: 'inherit' });
127-
} catch (loginErr) {
128-
log.error('');
129-
log.error(' DevTunnel login failed. To use tunnels, run:');
130-
log.error(' devtunnel user login');
131-
log.error('');
132-
log.error(' Or start without a tunnel:');
133-
log.error(' termbeam --no-tunnel');
134-
log.error('');
135-
return null;
126+
execFileSync(devtunnelCmd, ['user', 'login'], { stdio: 'inherit', timeout: 30000 });
127+
} catch {
128+
log.info('Browser login failed or unavailable, falling back to device code flow...');
129+
log.info('A code will be displayed — open the URL on any device to authenticate.');
130+
try {
131+
execFileSync(devtunnelCmd, ['user', 'login', '-d'], { stdio: 'inherit' });
132+
} catch (loginErr) {
133+
log.error('');
134+
log.error(' DevTunnel login failed. To use tunnels, run:');
135+
log.error(' devtunnel user login');
136+
log.error('');
137+
log.error(' Or start without a tunnel:');
138+
log.error(' termbeam --no-tunnel');
139+
log.error('');
140+
return null;
141+
}
136142
}
137143
}
138144

@@ -257,4 +263,4 @@ function cleanupTunnel() {
257263
}
258264
}
259265

260-
module.exports = { startTunnel, cleanupTunnel };
266+
module.exports = { startTunnel, cleanupTunnel, findDevtunnel };

0 commit comments

Comments
 (0)