Add robust fallback mechanism with timeout-based initialization

- Wrapped initial fit logic in comprehensive try-catch with multiple fallback strategies
- Added timeout-based fallback (2 seconds) to ensure terminal always gets initialized
- Enhanced error handling to prevent blank terminal on initialization failure
- Added cleanup of fallback timeout when WebSocket connects successfully
- Maintains all existing functionality and improves reliability

Bump version to 0.3.30

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
GitHub Copilot
2026-01-28 00:37:11 +00:00
parent 35aa0c0968
commit a3b0d46fa8
3 changed files with 69 additions and 17 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "textual-webterm"
version = "0.3.29"
version = "0.3.30"
description = "Serve terminal sessions over the web"
authors = ["Will McGugan <will@textualize.io>"]
license = "MIT"
+23
View File
@@ -14665,6 +14665,7 @@ class WebTerminal {
this.send(["resize", { width: fallback.cols, height: fallback.rows }]);
return;
}
try {
if (dims && this.isValidSize(dims.cols, dims.rows) && this.isTerminalReady()) {
this.terminal.resize(dims.cols, dims.rows);
this.resizeState.lastValidSize = dims;
@@ -14676,6 +14677,12 @@ class WebTerminal {
this.resizeState.lastValidSize = fallback;
this.send(["resize", { width: fallback.cols, height: fallback.rows }]);
}
} catch (e) {
console.warn(`Initial fit failed with exception: ${e.message}, using fallback`);
this.terminal.resize(fallback.cols, fallback.rows);
this.resizeState.lastValidSize = fallback;
this.send(["resize", { width: fallback.cols, height: fallback.rows }]);
}
};
window.requestAnimationFrame(() => attemptFitAndResize(0));
};
@@ -14684,6 +14691,22 @@ class WebTerminal {
} else {
init();
}
const fallbackTimeout = setTimeout(() => {
if (!this.resizeState.lastValidSize) {
console.warn("Initial fit timed out, applying fallback dimensions");
const fallback = { cols: 80, rows: 24 };
try {
this.terminal.resize(fallback.cols, fallback.rows);
this.resizeState.lastValidSize = fallback;
this.send(["resize", { width: fallback.cols, height: fallback.rows }]);
} catch (e) {
console.error("Fallback resize failed:", e);
}
}
}, 2000);
this.socket?.addEventListener("open", () => {
clearTimeout(fallbackTimeout);
});
this.terminal.focus();
});
this.socket.addEventListener("close", () => {
+29
View File
@@ -373,6 +373,8 @@ class WebTerminal {
}
// Validate dimensions and terminal readiness before applying
// Use a defensive approach with multiple fallback strategies
try {
if (dims && this.isValidSize(dims.cols, dims.rows) && this.isTerminalReady()) {
this.terminal.resize(dims.cols, dims.rows);
this.resizeState.lastValidSize = dims;
@@ -386,6 +388,13 @@ class WebTerminal {
this.resizeState.lastValidSize = fallback;
this.send(["resize", { width: fallback.cols, height: fallback.rows }]);
}
} catch (e) {
console.warn(`Initial fit failed with exception: ${e.message}, using fallback`);
// If anything goes wrong, use the fallback dimensions
this.terminal.resize(fallback.cols, fallback.rows);
this.resizeState.lastValidSize = fallback;
this.send(["resize", { width: fallback.cols, height: fallback.rows }]);
}
};
window.requestAnimationFrame(() => attemptFitAndResize(0));
@@ -397,6 +406,26 @@ class WebTerminal {
init();
}
// Add a timeout-based fallback in case the initial fit never succeeds
const fallbackTimeout = setTimeout(() => {
if (!this.resizeState.lastValidSize) {
console.warn("Initial fit timed out, applying fallback dimensions");
const fallback = { cols: 80, rows: 24 };
try {
this.terminal.resize(fallback.cols, fallback.rows);
this.resizeState.lastValidSize = fallback;
this.send(["resize", { width: fallback.cols, height: fallback.rows }]);
} catch (e) {
console.error("Fallback resize failed:", e);
}
}
}, 2000);
// Clean up timeout when WebSocket connects
this.socket?.addEventListener('open', () => {
clearTimeout(fallbackTimeout);
});
// Focus terminal
this.terminal.focus();
});