codehost 0.18.0 → 0.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/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/src/shared/signaling-client.ts +21 -0
- package/src/web/tunnel-client.ts +7 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [0.18.1](https://github.com/snomiao/codehost/compare/v0.18.0...v0.18.1) (2026-06-11)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **signaling:** abort connect attempts stuck in CONNECTING; guard tunnel stream enqueue ([b3ae0d1](https://github.com/snomiao/codehost/commit/b3ae0d11299a195b8d09e42355cd14a3b09b8d2f))
|
|
7
|
+
|
|
1
8
|
# [0.18.0](https://github.com/snomiao/codehost/compare/v0.17.0...v0.18.0) (2026-06-11)
|
|
2
9
|
|
|
3
10
|
|
package/package.json
CHANGED
|
@@ -37,6 +37,12 @@ export interface CloseInfo {
|
|
|
37
37
|
* open/close cycle becomes a sub-second reconnect storm. */
|
|
38
38
|
const STABLE_MS = 10_000;
|
|
39
39
|
|
|
40
|
+
/** Abort a connect attempt that hasn't opened by this deadline. Observed in the
|
|
41
|
+
* field (Chrome, page-load burst): a socket can sit in CONNECTING for minutes
|
|
42
|
+
* and never fire close — so without this, no retry ever runs, even though a
|
|
43
|
+
* freshly-created socket to the same room opens instantly. */
|
|
44
|
+
const CONNECT_TIMEOUT_MS = 10_000;
|
|
45
|
+
|
|
40
46
|
/**
|
|
41
47
|
* Thin WebSocket client for the signaling room. Runs unchanged in the browser
|
|
42
48
|
* and in Bun (both expose a global `WebSocket`). Auto-reconnects with backoff
|
|
@@ -71,7 +77,21 @@ export class SignalingClient {
|
|
|
71
77
|
const ws = new WebSocket(this.roomUrl());
|
|
72
78
|
this.ws = ws;
|
|
73
79
|
|
|
80
|
+
// A stuck CONNECTING socket never fires close on its own — abort it so the
|
|
81
|
+
// normal onclose -> backoff -> retry path takes over.
|
|
82
|
+
const connectTimer = setTimeout(() => {
|
|
83
|
+
if (ws.readyState === 0 /* CONNECTING */) {
|
|
84
|
+
try {
|
|
85
|
+
ws.close();
|
|
86
|
+
} catch {
|
|
87
|
+
// closing an unopened socket may throw in some runtimes — the
|
|
88
|
+
// onerror/onclose path still runs
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}, CONNECT_TIMEOUT_MS);
|
|
92
|
+
|
|
74
93
|
ws.onopen = () => {
|
|
94
|
+
clearTimeout(connectTimer);
|
|
75
95
|
this.openedAt = Date.now();
|
|
76
96
|
// Don't reset the backoff yet — only once the socket proves stable (see
|
|
77
97
|
// STABLE_MS). A handshake-then-drop network never reaches this timer, so
|
|
@@ -103,6 +123,7 @@ export class SignalingClient {
|
|
|
103
123
|
};
|
|
104
124
|
|
|
105
125
|
ws.onclose = (ev) => {
|
|
126
|
+
clearTimeout(connectTimer);
|
|
106
127
|
this.clearStableTimer();
|
|
107
128
|
this.stopHeartbeat();
|
|
108
129
|
const ms = this.openedAt ? Date.now() - this.openedAt : 0;
|
package/src/web/tunnel-client.ts
CHANGED
|
@@ -129,7 +129,13 @@ export class TunnelClient {
|
|
|
129
129
|
}),
|
|
130
130
|
);
|
|
131
131
|
},
|
|
132
|
-
onBody: (b) =>
|
|
132
|
+
onBody: (b) => {
|
|
133
|
+
try {
|
|
134
|
+
controller?.enqueue(b);
|
|
135
|
+
} catch {
|
|
136
|
+
// stream already closed/cancelled (consumer went away mid-body)
|
|
137
|
+
}
|
|
138
|
+
},
|
|
133
139
|
onEnd: () => {
|
|
134
140
|
try {
|
|
135
141
|
controller?.close();
|