@lifeaitools/clauth 1.4.8 → 1.5.0
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/cli/commands/serve.js +36 -4
- package/package.json +1 -1
package/cli/commands/serve.js
CHANGED
|
@@ -1217,8 +1217,25 @@ async function loadServices() {
|
|
|
1217
1217
|
err.style.display = "none";
|
|
1218
1218
|
grid.innerHTML = '<p class="loading">Loading…</p>';
|
|
1219
1219
|
|
|
1220
|
+
let status;
|
|
1221
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
1222
|
+
try {
|
|
1223
|
+
status = await Promise.race([
|
|
1224
|
+
fetch(BASE + "/status").then(r => r.json()),
|
|
1225
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), 8000))
|
|
1226
|
+
]);
|
|
1227
|
+
break;
|
|
1228
|
+
} catch (e) {
|
|
1229
|
+
if (attempt === 2) {
|
|
1230
|
+
err.textContent = "⚠ Could not load services — " + e.message;
|
|
1231
|
+
err.style.display = "block";
|
|
1232
|
+
grid.innerHTML = "";
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1220
1238
|
try {
|
|
1221
|
-
const status = await fetch(BASE + "/status").then(r => r.json());
|
|
1222
1239
|
if (status.locked) { showLockScreen(); return; }
|
|
1223
1240
|
if (status.error) throw new Error(status.error);
|
|
1224
1241
|
|
|
@@ -1758,8 +1775,16 @@ let tunnelPollTimer = null;
|
|
|
1758
1775
|
|
|
1759
1776
|
async function pollTunnel() {
|
|
1760
1777
|
if (tunnelPollTimer) clearInterval(tunnelPollTimer);
|
|
1778
|
+
// Give server 4s grace to run fetchTunnelConfig before showing "not_started" UI
|
|
1761
1779
|
const r = await apiFetch("/tunnel");
|
|
1762
|
-
if (r
|
|
1780
|
+
if (r && r.status !== "not_started") {
|
|
1781
|
+
renderTunnelPanel(r.status, r.url, r.error);
|
|
1782
|
+
} else {
|
|
1783
|
+
renderTunnelPanel("starting", null, null); // show spinner while server initialises
|
|
1784
|
+
await new Promise(res => setTimeout(res, 4000));
|
|
1785
|
+
const r2 = await apiFetch("/tunnel");
|
|
1786
|
+
if (r2) renderTunnelPanel(r2.status, r2.url, r2.error);
|
|
1787
|
+
}
|
|
1763
1788
|
// Poll every 3s; slow to 10s once live
|
|
1764
1789
|
tunnelPollTimer = setInterval(async () => {
|
|
1765
1790
|
const r = await apiFetch("/tunnel");
|
|
@@ -2440,7 +2465,11 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
2440
2465
|
}
|
|
2441
2466
|
|
|
2442
2467
|
async function startTunnel() {
|
|
2443
|
-
if (tunnelProc)
|
|
2468
|
+
if (tunnelProc) {
|
|
2469
|
+
// Already running — ensure status reflects reality (caller may have reset it to "starting")
|
|
2470
|
+
tunnelStatus = "live";
|
|
2471
|
+
return;
|
|
2472
|
+
}
|
|
2444
2473
|
tunnelUrl = null;
|
|
2445
2474
|
tunnelError = null;
|
|
2446
2475
|
|
|
@@ -3408,7 +3437,10 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3408
3437
|
try {
|
|
3409
3438
|
const pwEscaped = pw.replace(/'/g, "''");
|
|
3410
3439
|
const psExpr = `[Convert]::ToBase64String([Security.Cryptography.ProtectedData]::Protect([Text.Encoding]::UTF8.GetBytes('${pwEscaped}'),$null,'CurrentUser'))`;
|
|
3411
|
-
const
|
|
3440
|
+
const psExe = process.env.SystemRoot
|
|
3441
|
+
? `${process.env.SystemRoot}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`
|
|
3442
|
+
: "powershell.exe";
|
|
3443
|
+
const encrypted = execSyncTop(`"${psExe}" -NoProfile -Command "${psExpr}"`, { encoding: "utf8", timeout: 5000 }).trim();
|
|
3412
3444
|
fs.writeFileSync(bootKeyPath, encrypted, "utf8");
|
|
3413
3445
|
const sealLog = `[${new Date().toISOString()}] Auto-sealed boot.key via DPAPI (crash recovery enabled)\n`;
|
|
3414
3446
|
try { fs.appendFileSync(LOG_FILE, sealLog); } catch {}
|