termbeam 1.17.8 → 1.18.1
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/package.json +1 -1
- package/public/assets/{_basePickBy-Bx4czgjK.js → _basePickBy-SVV3-IdA.js} +1 -1
- package/public/assets/{_baseUniq-B_xhLk1b.js → _baseUniq-DOa_cDXJ.js} +1 -1
- package/public/assets/{arc-_Z6A8o27.js → arc-CiPooz6h.js} +1 -1
- package/public/assets/{architectureDiagram-2XIMDMQ5-DDtL0DSL.js → architectureDiagram-2XIMDMQ5-DLhsY97x.js} +1 -1
- package/public/assets/{blockDiagram-WCTKOSBZ-DYgWhdwH.js → blockDiagram-WCTKOSBZ-BmfWKjiE.js} +1 -1
- package/public/assets/{c4Diagram-IC4MRINW-DlbE0l99.js → c4Diagram-IC4MRINW-CHJjiNgt.js} +1 -1
- package/public/assets/channel-BK2nwbl-.js +1 -0
- package/public/assets/{chunk-4BX2VUAB-BbtQtJab.js → chunk-4BX2VUAB-DslNFup8.js} +1 -1
- package/public/assets/{chunk-55IACEB6-Dk_FjBN6.js → chunk-55IACEB6-DF8ZBVw6.js} +1 -1
- package/public/assets/{chunk-FMBD7UC4-BSOODOC9.js → chunk-FMBD7UC4-CVO2u-Sv.js} +1 -1
- package/public/assets/{chunk-JSJVCQXG-B71Oj-xI.js → chunk-JSJVCQXG-CdSwCmzy.js} +1 -1
- package/public/assets/{chunk-KX2RTZJC-Bv_BWOZR.js → chunk-KX2RTZJC-DR85cVBM.js} +1 -1
- package/public/assets/{chunk-NQ4KR5QH-NrpJgmB3.js → chunk-NQ4KR5QH-DENB8fT9.js} +1 -1
- package/public/assets/{chunk-QZHKN3VN-BmrKPCfl.js → chunk-QZHKN3VN-D1hlvsPG.js} +1 -1
- package/public/assets/{chunk-WL4C6EOR-CpglQTvf.js → chunk-WL4C6EOR-BFkfV9d-.js} +1 -1
- package/public/assets/classDiagram-VBA2DB6C-Ca3s5d8r.js +1 -0
- package/public/assets/classDiagram-v2-RAHNMMFH-Ca3s5d8r.js +1 -0
- package/public/assets/clone-Zyw2C-Y3.js +1 -0
- package/public/assets/{cose-bilkent-S5V4N54A-DYL0lt4P.js → cose-bilkent-S5V4N54A-BHgn8K1Z.js} +1 -1
- package/public/assets/{dagre-KLK3FWXG-BNyGQfuq.js → dagre-KLK3FWXG-CK-UftHZ.js} +1 -1
- package/public/assets/{diagram-E7M64L7V-BueAxddl.js → diagram-E7M64L7V-B7XX1Mqr.js} +1 -1
- package/public/assets/{diagram-IFDJBPK2-Dr-u91gt.js → diagram-IFDJBPK2-DtSlXz7u.js} +1 -1
- package/public/assets/{diagram-P4PSJMXO-C1T2kE4V.js → diagram-P4PSJMXO-Cb0uoPeh.js} +1 -1
- package/public/assets/{erDiagram-INFDFZHY-CO2EjQ8J.js → erDiagram-INFDFZHY-D2aAhxDx.js} +1 -1
- package/public/assets/{flowDiagram-PKNHOUZH-T00X36Vw.js → flowDiagram-PKNHOUZH-BxCqn1aV.js} +1 -1
- package/public/assets/{ganttDiagram-A5KZAMGK-DgBggnkU.js → ganttDiagram-A5KZAMGK-oBrRehQA.js} +1 -1
- package/public/assets/{gitGraphDiagram-K3NZZRJ6-BSWTPOpC.js → gitGraphDiagram-K3NZZRJ6-CMuK7hOw.js} +1 -1
- package/public/assets/{graph-BT-QdyLg.js → graph-NJUd-2rr.js} +1 -1
- package/public/assets/{index-XvAS6GsK.css → index-BzV_FYAW.css} +1 -1
- package/public/assets/{index-CZRetRoe.js → index-DBnflEQZ.js} +106 -106
- package/public/assets/{infoDiagram-LFFYTUFH-Dj6pwKgk.js → infoDiagram-LFFYTUFH-C0cd4K10.js} +1 -1
- package/public/assets/{ishikawaDiagram-PHBUUO56-Db8O4ufB.js → ishikawaDiagram-PHBUUO56-Ny_4n8vD.js} +1 -1
- package/public/assets/{journeyDiagram-4ABVD52K-BpZ_Yrqs.js → journeyDiagram-4ABVD52K-2QGufcXt.js} +1 -1
- package/public/assets/{kanban-definition-K7BYSVSG-D3zRUDJP.js → kanban-definition-K7BYSVSG-DDGFShX4.js} +1 -1
- package/public/assets/{layout-BI7uDMCL.js → layout-DTAwaKXg.js} +1 -1
- package/public/assets/{linear-DgP566HT.js → linear-CSYWJnE5.js} +1 -1
- package/public/assets/{mindmap-definition-YRQLILUH-BXNxkbvs.js → mindmap-definition-YRQLILUH-C6Jy7Tz1.js} +1 -1
- package/public/assets/{pieDiagram-SKSYHLDU-CuMBI_xo.js → pieDiagram-SKSYHLDU-DCNv1DYe.js} +1 -1
- package/public/assets/{quadrantDiagram-337W2JSQ-7_kXk56H.js → quadrantDiagram-337W2JSQ-DWGyMcZ6.js} +1 -1
- package/public/assets/{requirementDiagram-Z7DCOOCP-Dc4encPC.js → requirementDiagram-Z7DCOOCP-BC1_RS6p.js} +1 -1
- package/public/assets/{sankeyDiagram-WA2Y5GQK-DSlUG_VS.js → sankeyDiagram-WA2Y5GQK-GoTjgmGo.js} +1 -1
- package/public/assets/{sequenceDiagram-2WXFIKYE-DaWz5El2.js → sequenceDiagram-2WXFIKYE-CjTa5Eua.js} +1 -1
- package/public/assets/{stateDiagram-RAJIS63D-B4oQefUl.js → stateDiagram-RAJIS63D-wf6b0MTk.js} +1 -1
- package/public/assets/stateDiagram-v2-FVOUBMTO-lYMaTr7v.js +1 -0
- package/public/assets/{timeline-definition-YZTLITO2-D9zlUa7w.js → timeline-definition-YZTLITO2-BHWYxexH.js} +1 -1
- package/public/assets/{treemap-KZPCXAKY-RGFpoXIT.js → treemap-KZPCXAKY-0OLZO-76.js} +1 -1
- package/public/assets/{vennDiagram-LZ73GAT5-D5gYnx59.js → vennDiagram-LZ73GAT5-DzlX55oz.js} +1 -1
- package/public/assets/{xychartDiagram-JWTSCODW-C7kxjkz6.js → xychartDiagram-JWTSCODW-DafJ-a-f.js} +1 -1
- package/public/index.html +2 -2
- package/public/sw.js +2 -2
- package/src/server/index.js +43 -15
- package/src/server/routes.js +33 -9
- package/src/server/sessions.js +20 -0
- package/src/tunnel/index.js +200 -55
- package/public/assets/channel-Cw6U4HD8.js +0 -1
- package/public/assets/classDiagram-VBA2DB6C-B8Ph5aUJ.js +0 -1
- package/public/assets/classDiagram-v2-RAHNMMFH-B8Ph5aUJ.js +0 -1
- package/public/assets/clone-tNYKz33q.js +0 -1
- package/public/assets/stateDiagram-v2-FVOUBMTO-C4ooUxXR.js +0 -1
package/src/tunnel/index.js
CHANGED
|
@@ -21,19 +21,77 @@ let restartAttempts = 0;
|
|
|
21
21
|
let isRestarting = false;
|
|
22
22
|
let restartTimer = null;
|
|
23
23
|
|
|
24
|
+
// --- Auth-wait state ---
|
|
25
|
+
let waitingForAuth = false;
|
|
26
|
+
let authCheckInterval = null;
|
|
27
|
+
let expiryWarned = false;
|
|
28
|
+
|
|
24
29
|
const HEALTH_CHECK_INTERVAL = 30_000; // 30s between checks
|
|
25
30
|
const HEALTH_CHECK_GRACE = 2; // 2 consecutive failures before restart
|
|
26
31
|
const MAX_RESTART_ATTEMPTS = 10;
|
|
27
32
|
const BACKOFF_DELAYS = [1000, 2000, 5000, 10_000, 15_000, 30_000]; // then stays at 30s
|
|
33
|
+
const AUTH_CHECK_INTERVAL = 30_000; // 30s between auth re-checks
|
|
34
|
+
const TOKEN_EXPIRY_WARN_SECONDS = 3600; // warn at 1 hour remaining
|
|
35
|
+
|
|
36
|
+
const AUTH_ERROR_PATTERNS = ['login required', 'not logged in', 'sign in required'];
|
|
28
37
|
|
|
29
38
|
const SAFE_ID_RE = /^[a-zA-Z0-9._-]+$/;
|
|
30
39
|
|
|
31
40
|
const DEVICE_CODE_INITIAL_TIMEOUT = 15000;
|
|
32
41
|
const DEVICE_CODE_AUTH_TIMEOUT = 120000;
|
|
33
42
|
|
|
43
|
+
function isAuthError(message) {
|
|
44
|
+
const lower = (message || '').toLowerCase();
|
|
45
|
+
return AUTH_ERROR_PATTERNS.some((p) => lower.includes(p));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function isLoggedIn() {
|
|
49
|
+
try {
|
|
50
|
+
const out = execFileSync(devtunnelCmd, ['user', 'show'], {
|
|
51
|
+
encoding: 'utf-8',
|
|
52
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
53
|
+
timeout: 10_000,
|
|
54
|
+
});
|
|
55
|
+
return out && !out.toLowerCase().includes('not logged in');
|
|
56
|
+
} catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getLoginInfo() {
|
|
62
|
+
try {
|
|
63
|
+
const out = execFileSync(devtunnelCmd, ['user', 'show', '-v'], {
|
|
64
|
+
encoding: 'utf-8',
|
|
65
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
66
|
+
timeout: 10_000,
|
|
67
|
+
});
|
|
68
|
+
return parseLoginInfo(out);
|
|
69
|
+
} catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function parseLoginInfo(output) {
|
|
75
|
+
if (!output || output.toLowerCase().includes('not logged in')) return null;
|
|
76
|
+
|
|
77
|
+
let provider = 'unknown';
|
|
78
|
+
if (output.toLowerCase().includes('github')) provider = 'github';
|
|
79
|
+
else if (output.toLowerCase().includes('microsoft')) provider = 'microsoft';
|
|
80
|
+
|
|
81
|
+
// Parse "Token lifetime: H:MM:SS" from verbose output
|
|
82
|
+
let tokenLifetimeSeconds = null;
|
|
83
|
+
const ltMatch = output.match(/Token lifetime:\s*(\d+):(\d+):(\d+)/);
|
|
84
|
+
if (ltMatch) {
|
|
85
|
+
tokenLifetimeSeconds =
|
|
86
|
+
parseInt(ltMatch[1], 10) * 3600 + parseInt(ltMatch[2], 10) * 60 + parseInt(ltMatch[3], 10);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return { provider, tokenLifetimeSeconds };
|
|
90
|
+
}
|
|
91
|
+
|
|
34
92
|
function deviceCodeLogin(cmd) {
|
|
35
93
|
return new Promise((resolve, reject) => {
|
|
36
|
-
const proc = spawn(cmd, ['user', 'login', '-d'], {
|
|
94
|
+
const proc = spawn(cmd, ['user', 'login', '-e', '-d'], {
|
|
37
95
|
stdio: ['inherit', 'pipe', 'pipe'],
|
|
38
96
|
});
|
|
39
97
|
|
|
@@ -152,7 +210,7 @@ let isPersisted = false;
|
|
|
152
210
|
// --- Watchdog: health check & auto-restart ---
|
|
153
211
|
|
|
154
212
|
function checkTunnelHealth() {
|
|
155
|
-
if (!tunnelId || !tunnelProc || isRestarting) return;
|
|
213
|
+
if (!tunnelId || !tunnelProc || isRestarting || waitingForAuth) return;
|
|
156
214
|
|
|
157
215
|
const abortCtrl = new AbortController();
|
|
158
216
|
const timer = setTimeout(() => abortCtrl.abort(), 10_000);
|
|
@@ -165,6 +223,20 @@ function checkTunnelHealth() {
|
|
|
165
223
|
clearTimeout(timer);
|
|
166
224
|
|
|
167
225
|
if (err) {
|
|
226
|
+
// Auth errors are handled separately — no restart countdown
|
|
227
|
+
if (isAuthError(err.message) || isAuthError(err.stderr)) {
|
|
228
|
+
handleAuthExpiration();
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// "Tunnel not found" can mean the user's auth expired (CLI can't
|
|
233
|
+
// query the tunnel without valid credentials). Check login status
|
|
234
|
+
// to distinguish from a genuinely deleted tunnel.
|
|
235
|
+
if (!isLoggedIn()) {
|
|
236
|
+
handleAuthExpiration();
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
168
240
|
consecutiveFailures++;
|
|
169
241
|
log.warn(
|
|
170
242
|
`Tunnel health check error: ${err.message} (${consecutiveFailures}/${HEALTH_CHECK_GRACE})`,
|
|
@@ -193,6 +265,9 @@ function checkTunnelHealth() {
|
|
|
193
265
|
log.info(`Tunnel health restored (${hostConns} host connection(s))`);
|
|
194
266
|
}
|
|
195
267
|
consecutiveFailures = 0;
|
|
268
|
+
|
|
269
|
+
// Check token expiry while tunnel is healthy
|
|
270
|
+
checkTokenExpiry();
|
|
196
271
|
return;
|
|
197
272
|
}
|
|
198
273
|
|
|
@@ -209,6 +284,24 @@ function checkTunnelHealth() {
|
|
|
209
284
|
);
|
|
210
285
|
}
|
|
211
286
|
|
|
287
|
+
function checkTokenExpiry() {
|
|
288
|
+
const info = getLoginInfo();
|
|
289
|
+
if (!info || info.tokenLifetimeSeconds === null) return;
|
|
290
|
+
|
|
291
|
+
const remaining = info.tokenLifetimeSeconds;
|
|
292
|
+
|
|
293
|
+
if (remaining <= TOKEN_EXPIRY_WARN_SECONDS && !expiryWarned) {
|
|
294
|
+
expiryWarned = true;
|
|
295
|
+
const minutes = Math.round(remaining / 60);
|
|
296
|
+
log.warn(`DevTunnel token expires in ${minutes}m (will auto-refresh)`);
|
|
297
|
+
} else if (remaining > TOKEN_EXPIRY_WARN_SECONDS && expiryWarned) {
|
|
298
|
+
expiryWarned = false;
|
|
299
|
+
log.info('DevTunnel token was auto-refreshed');
|
|
300
|
+
} else if (remaining > TOKEN_EXPIRY_WARN_SECONDS) {
|
|
301
|
+
expiryWarned = false;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
212
305
|
function startHealthCheck() {
|
|
213
306
|
stopHealthCheck();
|
|
214
307
|
consecutiveFailures = 0;
|
|
@@ -226,30 +319,74 @@ function stopHealthCheck() {
|
|
|
226
319
|
function handleTunnelFailure() {
|
|
227
320
|
if (isRestarting) return;
|
|
228
321
|
stopHealthCheck();
|
|
322
|
+
killTunnelProc();
|
|
229
323
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
324
|
+
tunnelEvents.emit('disconnected');
|
|
325
|
+
scheduleRestart();
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// --- Auth-expiration handling ---
|
|
329
|
+
|
|
330
|
+
function killTunnelProc() {
|
|
331
|
+
if (!tunnelProc) return;
|
|
332
|
+
try {
|
|
333
|
+
if (process.platform === 'win32' && tunnelProc.pid) {
|
|
334
|
+
try {
|
|
335
|
+
execFileSync('taskkill', ['/pid', String(tunnelProc.pid), '/T', '/F'], {
|
|
336
|
+
stdio: 'pipe',
|
|
337
|
+
timeout: 5000,
|
|
338
|
+
});
|
|
339
|
+
} catch {
|
|
340
|
+
/* best effort */
|
|
244
341
|
}
|
|
245
|
-
}
|
|
246
|
-
|
|
342
|
+
} else {
|
|
343
|
+
tunnelProc.kill('SIGKILL');
|
|
247
344
|
}
|
|
248
|
-
|
|
345
|
+
} catch {
|
|
346
|
+
/* best effort */
|
|
249
347
|
}
|
|
348
|
+
tunnelProc = null;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function handleAuthExpiration() {
|
|
352
|
+
if (waitingForAuth) return;
|
|
353
|
+
stopHealthCheck();
|
|
354
|
+
killTunnelProc();
|
|
250
355
|
|
|
251
356
|
tunnelEvents.emit('disconnected');
|
|
252
|
-
|
|
357
|
+
tunnelEvents.emit('auth-expired');
|
|
358
|
+
startAuthWait();
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function startAuthWait() {
|
|
362
|
+
if (waitingForAuth) return;
|
|
363
|
+
waitingForAuth = true;
|
|
364
|
+
isRestarting = false;
|
|
365
|
+
restartAttempts = 0;
|
|
366
|
+
consecutiveFailures = 0;
|
|
367
|
+
|
|
368
|
+
log.warn('DevTunnel auth token expired (Microsoft tokens expire after a few days).');
|
|
369
|
+
log.warn('Tunnel is paused — re-authenticate on the host machine to restore:');
|
|
370
|
+
log.warn(' devtunnel user login -d');
|
|
371
|
+
log.warn('Tunnel will auto-reconnect once auth is restored.');
|
|
372
|
+
|
|
373
|
+
authCheckInterval = setInterval(() => {
|
|
374
|
+
if (isLoggedIn()) {
|
|
375
|
+
log.info('DevTunnel auth restored — resuming tunnel');
|
|
376
|
+
stopAuthWait();
|
|
377
|
+
tunnelEvents.emit('auth-restored');
|
|
378
|
+
scheduleRestart();
|
|
379
|
+
}
|
|
380
|
+
}, AUTH_CHECK_INTERVAL);
|
|
381
|
+
authCheckInterval.unref();
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function stopAuthWait() {
|
|
385
|
+
waitingForAuth = false;
|
|
386
|
+
if (authCheckInterval) {
|
|
387
|
+
clearInterval(authCheckInterval);
|
|
388
|
+
authCheckInterval = null;
|
|
389
|
+
}
|
|
253
390
|
}
|
|
254
391
|
|
|
255
392
|
function scheduleRestart() {
|
|
@@ -271,6 +408,15 @@ function scheduleRestart() {
|
|
|
271
408
|
|
|
272
409
|
restartTimer = setTimeout(async () => {
|
|
273
410
|
restartTimer = null;
|
|
411
|
+
|
|
412
|
+
// If auth expired since restart was scheduled, switch to auth-wait mode
|
|
413
|
+
if (!isLoggedIn()) {
|
|
414
|
+
log.warn('DevTunnel auth expired during restart — waiting for re-authentication');
|
|
415
|
+
isRestarting = false;
|
|
416
|
+
handleAuthExpiration();
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
|
|
274
420
|
try {
|
|
275
421
|
const result = await hostTunnel();
|
|
276
422
|
if (result) {
|
|
@@ -368,21 +514,30 @@ async function startTunnel(port, options = {}) {
|
|
|
368
514
|
|
|
369
515
|
log.info('Starting devtunnel...');
|
|
370
516
|
try {
|
|
371
|
-
// Ensure user is logged in
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
517
|
+
// Ensure user is logged in. Prefer Entra over GitHub — Entra tokens auto-refresh
|
|
518
|
+
// for weeks via MSAL, while GitHub tokens expire after 8 hours.
|
|
519
|
+
let loggedIn = isLoggedIn();
|
|
520
|
+
const loginInfo = loggedIn ? getLoginInfo() : null;
|
|
521
|
+
|
|
522
|
+
if (loggedIn && loginInfo) {
|
|
523
|
+
const { provider, tokenLifetimeSeconds } = loginInfo;
|
|
524
|
+
if (provider === 'github') {
|
|
525
|
+
log.warn(
|
|
526
|
+
'Logged in with GitHub — tokens expire every 8 hours. ' +
|
|
527
|
+
'For longer sessions, use: devtunnel user login -e -d',
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
if (tokenLifetimeSeconds !== null) {
|
|
531
|
+
const h = Math.floor(tokenLifetimeSeconds / 3600);
|
|
532
|
+
const m = Math.round((tokenLifetimeSeconds % 3600) / 60);
|
|
533
|
+
log.info(`DevTunnel token expires in ${h}h ${m}m`);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
381
536
|
|
|
382
537
|
if (!loggedIn) {
|
|
383
|
-
log.info('
|
|
538
|
+
log.info('Logging in to DevTunnel with Microsoft Entra (recommended for long sessions)...');
|
|
384
539
|
try {
|
|
385
|
-
execFileSync(devtunnelCmd, ['user', 'login'], { stdio: 'inherit', timeout: 30000 });
|
|
540
|
+
execFileSync(devtunnelCmd, ['user', 'login', '-e'], { stdio: 'inherit', timeout: 30000 });
|
|
386
541
|
} catch {
|
|
387
542
|
log.info('Browser login failed or unavailable, falling back to device code flow...');
|
|
388
543
|
log.info('A code will be displayed — open the URL on any device to authenticate.');
|
|
@@ -391,7 +546,7 @@ async function startTunnel(port, options = {}) {
|
|
|
391
546
|
} catch (_loginErr) {
|
|
392
547
|
log.error('');
|
|
393
548
|
log.error(' DevTunnel login failed. To use tunnels, run:');
|
|
394
|
-
log.error(' devtunnel user login');
|
|
549
|
+
log.error(' devtunnel user login -e -d');
|
|
395
550
|
log.error('');
|
|
396
551
|
log.error(' Or start without a tunnel:');
|
|
397
552
|
log.error(' termbeam --no-tunnel');
|
|
@@ -480,8 +635,9 @@ async function startTunnel(port, options = {}) {
|
|
|
480
635
|
}
|
|
481
636
|
|
|
482
637
|
function cleanupTunnel() {
|
|
483
|
-
// Stop watchdog
|
|
638
|
+
// Stop watchdog and auth-wait to prevent restart during cleanup
|
|
484
639
|
stopHealthCheck();
|
|
640
|
+
stopAuthWait();
|
|
485
641
|
isRestarting = true; // prevent exit handler from restarting
|
|
486
642
|
if (restartTimer) {
|
|
487
643
|
clearTimeout(restartTimer);
|
|
@@ -489,26 +645,7 @@ function cleanupTunnel() {
|
|
|
489
645
|
}
|
|
490
646
|
|
|
491
647
|
const id = tunnelId;
|
|
492
|
-
|
|
493
|
-
try {
|
|
494
|
-
// On Windows, kill the process tree to ensure all children die
|
|
495
|
-
if (process.platform === 'win32' && tunnelProc.pid) {
|
|
496
|
-
try {
|
|
497
|
-
execFileSync('taskkill', ['/pid', String(tunnelProc.pid), '/T', '/F'], {
|
|
498
|
-
stdio: 'pipe',
|
|
499
|
-
timeout: 5000,
|
|
500
|
-
});
|
|
501
|
-
} catch {
|
|
502
|
-
/* best effort */
|
|
503
|
-
}
|
|
504
|
-
} else {
|
|
505
|
-
tunnelProc.kill('SIGKILL');
|
|
506
|
-
}
|
|
507
|
-
} catch {
|
|
508
|
-
/* best effort */
|
|
509
|
-
}
|
|
510
|
-
tunnelProc = null;
|
|
511
|
-
}
|
|
648
|
+
killTunnelProc();
|
|
512
649
|
if (id) {
|
|
513
650
|
tunnelId = null;
|
|
514
651
|
if (isPersisted) {
|
|
@@ -527,6 +664,14 @@ function cleanupTunnel() {
|
|
|
527
664
|
consecutiveFailures = 0;
|
|
528
665
|
restartAttempts = 0;
|
|
529
666
|
isRestarting = false;
|
|
667
|
+
expiryWarned = false;
|
|
530
668
|
}
|
|
531
669
|
|
|
532
|
-
module.exports = {
|
|
670
|
+
module.exports = {
|
|
671
|
+
startTunnel,
|
|
672
|
+
cleanupTunnel,
|
|
673
|
+
findDevtunnel,
|
|
674
|
+
tunnelEvents,
|
|
675
|
+
getLoginInfo,
|
|
676
|
+
parseLoginInfo,
|
|
677
|
+
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{aq as o,ar as n}from"./index-CZRetRoe.js";const t=(r,a)=>o.lang.round(n.parse(r)[a]);export{t as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-WL4C6EOR-CpglQTvf.js";import{_ as i}from"./index-CZRetRoe.js";import"./chunk-FMBD7UC4-BSOODOC9.js";import"./chunk-JSJVCQXG-B71Oj-xI.js";import"./chunk-55IACEB6-Dk_FjBN6.js";import"./chunk-KX2RTZJC-Bv_BWOZR.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-WL4C6EOR-CpglQTvf.js";import{_ as i}from"./index-CZRetRoe.js";import"./chunk-FMBD7UC4-BSOODOC9.js";import"./chunk-JSJVCQXG-B71Oj-xI.js";import"./chunk-55IACEB6-Dk_FjBN6.js";import"./chunk-KX2RTZJC-Bv_BWOZR.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{b as r}from"./_baseUniq-B_xhLk1b.js";var e=4;function a(o){return r(o,e)}export{a as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as t,b as r,a,S as s}from"./chunk-NQ4KR5QH-NrpJgmB3.js";import{_ as i}from"./index-CZRetRoe.js";import"./chunk-55IACEB6-Dk_FjBN6.js";import"./chunk-KX2RTZJC-Bv_BWOZR.js";var l={parser:a,get db(){return new s(2)},renderer:r,styles:t,init:i(e=>{e.state||(e.state={}),e.state.arrowMarkerAbsolute=e.arrowMarkerAbsolute},"init")};export{l as diagram};
|