@cplieger/web-terminal-engine 5.0.5 → 5.0.8
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/jsr.json +1 -1
- package/package.json +2 -2
- package/src/connection.ts +15 -1
- package/src/store.ts +23 -0
package/jsr.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cplieger/web-terminal-engine",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"typecheck": "tsc -p tsconfig.json",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"esbuild": "0.28.2",
|
|
22
22
|
"eslint": "10.8.1",
|
|
23
23
|
"fast-check": "4.9.0",
|
|
24
|
-
"happy-dom": "20.11.
|
|
24
|
+
"happy-dom": "20.11.6",
|
|
25
25
|
"pngjs": "7.0.0",
|
|
26
26
|
"prettier": "3.9.6",
|
|
27
27
|
"typescript": "npm:@typescript/typescript6@6.0.2",
|
package/src/connection.ts
CHANGED
|
@@ -782,7 +782,21 @@ function retransmitOutbox(sock: WebSocket, upgraded: boolean, st: ResumeState):
|
|
|
782
782
|
}
|
|
783
783
|
|
|
784
784
|
function scheduleReconnect(): void {
|
|
785
|
-
|
|
785
|
+
// Nothing to schedule when the state already owns a path back to a socket: a
|
|
786
|
+
// backoff timer is pending ("reconnecting"), or a socket exists that will
|
|
787
|
+
// drive its own retry from its close handler or its connect timeout
|
|
788
|
+
// ("connecting"/"connected"). Both callers set "disconnected" before calling
|
|
789
|
+
// cb.onClose(), so a consumer that reconnects from its own close hook lands
|
|
790
|
+
// here at "connecting" — and scheduling over it would OVERWRITE connState,
|
|
791
|
+
// hiding that socket from connect()'s double-call guard, which then never
|
|
792
|
+
// aborts it: the timer's connect() adds a second live socket with the first
|
|
793
|
+
// one's listeners still bound, i.e. the duplicate server connection and
|
|
794
|
+
// double delivery documented inside connect().
|
|
795
|
+
if (
|
|
796
|
+
connState.status === "reconnecting" ||
|
|
797
|
+
connState.status === "connecting" ||
|
|
798
|
+
connState.status === "connected"
|
|
799
|
+
) {
|
|
786
800
|
return;
|
|
787
801
|
}
|
|
788
802
|
const step = nextBackoffDelay(reconnectDelay);
|
package/src/store.ts
CHANGED
|
@@ -1826,6 +1826,17 @@ export class LineStore {
|
|
|
1826
1826
|
if (this.highest < 0) {
|
|
1827
1827
|
return;
|
|
1828
1828
|
}
|
|
1829
|
+
// No window established yet — the descriptor is still the initial base
|
|
1830
|
+
// 0/height 0, whose bottom row is -1, below every index a line can hold.
|
|
1831
|
+
// This whole pass rests on "the window's bottom row is the most recent line
|
|
1832
|
+
// in the terminal", which says nothing at all when there is no window: a
|
|
1833
|
+
// resume replays history BEFORE the screen frame describing the window, so
|
|
1834
|
+
// taking -1 as the tail bound strands that replay and forgets it, silently
|
|
1835
|
+
// (this path is not a trim, so no marker explains it). Same test `inWindow`
|
|
1836
|
+
// and applyScroll's alt gate use to ask whether a window exists at all.
|
|
1837
|
+
if (this.win.height <= 0) {
|
|
1838
|
+
return;
|
|
1839
|
+
}
|
|
1829
1840
|
const windowBottom = this.win.base + this.win.height - 1;
|
|
1830
1841
|
if (this.highest <= windowBottom) {
|
|
1831
1842
|
return;
|
|
@@ -2008,6 +2019,18 @@ export class LineStore {
|
|
|
2008
2019
|
}
|
|
2009
2020
|
|
|
2010
2021
|
private updateWindow(msg: ScreenMessage): void {
|
|
2022
|
+
// A base that is not a non-negative integer is not a screen position — the
|
|
2023
|
+
// same validity test markUnconfirmedFrom applies to this very value — so it
|
|
2024
|
+
// must not redefine the window's shape, for the same reason a rows-less
|
|
2025
|
+
// frame must not: `base + height - 1` lands below every retained index, and
|
|
2026
|
+
// truncateBelowWindow then hands the WHOLE store over as stranded past the
|
|
2027
|
+
// live window. That is the silent wipe applyScreen's rows-less guard
|
|
2028
|
+
// records, reached with rows present, and just as silent (this path is not a
|
|
2029
|
+
// trim, so no marker explains the missing transcript). The frame's
|
|
2030
|
+
// addressable rows still apply through applyLine's guard 1.
|
|
2031
|
+
if (!Number.isInteger(msg.base) || msg.base < 0) {
|
|
2032
|
+
return;
|
|
2033
|
+
}
|
|
2011
2034
|
const next: WindowState = {
|
|
2012
2035
|
base: msg.base,
|
|
2013
2036
|
height: msg.rows.length,
|