codehost 0.10.0 → 0.11.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/.claude/scheduled_tasks.lock +1 -0
- package/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/src/web/discovery.tsx +54 -12
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"sessionId":"f8e4e571-944e-43d7-bbfa-267a5251e41c","pid":87968,"procStart":"Mon Jun 8 09:46:02 2026","acquiredAt":1780974562147}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [0.11.0](https://github.com/snomiao/codehost/compare/v0.10.0...v0.11.0) (2026-06-09)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **web:** update URL on Connect + Back returns to the list ([7258a16](https://github.com/snomiao/codehost/commit/7258a168a0bcc1d476aab8a7f3fcd81f35ccfcb5))
|
|
7
|
+
|
|
1
8
|
# [0.10.0](https://github.com/snomiao/codehost/compare/v0.9.1...v0.10.0) (2026-06-09)
|
|
2
9
|
|
|
3
10
|
|
package/package.json
CHANGED
package/src/web/discovery.tsx
CHANGED
|
@@ -176,6 +176,11 @@ export function Discovery() {
|
|
|
176
176
|
const activePeerRef = useRef<string | null>(null);
|
|
177
177
|
const activeRoomRef = useRef<string | null>(null);
|
|
178
178
|
const sendersRef = useRef<Map<string, (to: string, data: unknown) => void>>(new Map());
|
|
179
|
+
// Whether the live connection pushed a history entry (so Disconnect/Back can
|
|
180
|
+
// pop it), and whether we're currently *viewing* a workspace (so popstate only
|
|
181
|
+
// tears down from the iframe view, not during a mid-connect URL revert).
|
|
182
|
+
const pushedRef = useRef(false);
|
|
183
|
+
const viewingRef = useRef(false);
|
|
179
184
|
|
|
180
185
|
// Deep-link resolution (/gh/<owner>/<repo>/... or /dev/<path>): parse once,
|
|
181
186
|
// auto-connect when a matching server appears, remember the opened folder.
|
|
@@ -213,6 +218,13 @@ export function Discovery() {
|
|
|
213
218
|
const folder = activeFolderRef.current;
|
|
214
219
|
setTimeout(() => setIframeSrc(`/vs/${peerId}/${folderQuery(folder)}`), 400);
|
|
215
220
|
});
|
|
221
|
+
// Back / Cmd+Left from a workspace returns to the list: the browser restores
|
|
222
|
+
// the previous URL and we drop the connection. Only when actually viewing —
|
|
223
|
+
// a mid-connect URL revert (failed dial) must leave the list state untouched.
|
|
224
|
+
const onPopState = () => {
|
|
225
|
+
if (viewingRef.current) teardownConn();
|
|
226
|
+
};
|
|
227
|
+
window.addEventListener("popstate", onPopState);
|
|
216
228
|
// A valid token in the URL fragment (#t=<token>) joins the room and turns on
|
|
217
229
|
// single-server auto-connect for it; consume it from the address bar after,
|
|
218
230
|
// so the secret isn't left visible or re-applied on a manual reload.
|
|
@@ -242,6 +254,8 @@ export function Discovery() {
|
|
|
242
254
|
}
|
|
243
255
|
}
|
|
244
256
|
}
|
|
257
|
+
|
|
258
|
+
return () => window.removeEventListener("popstate", onPopState);
|
|
245
259
|
}, []);
|
|
246
260
|
|
|
247
261
|
// Auto-connect once discovery turns up a match: a deep-link target across any
|
|
@@ -291,8 +305,19 @@ export function Discovery() {
|
|
|
291
305
|
setActivePeerId(server.peerId);
|
|
292
306
|
activePeerRef.current = server.peerId;
|
|
293
307
|
activeRoomRef.current = room;
|
|
308
|
+
viewingRef.current = false;
|
|
294
309
|
setConnState("connecting");
|
|
295
310
|
|
|
311
|
+
// Update the address bar the instant Connect is clicked (don't wait for the
|
|
312
|
+
// WebRTC handshake) and push a history entry, so Back / Cmd+Left returns to
|
|
313
|
+
// the list. Reverted if the connection fails.
|
|
314
|
+
const openFolder = folder ?? server.meta?.cwd;
|
|
315
|
+
const targetPath = shareablePathFor(server, openFolder);
|
|
316
|
+
const pushed = !!targetPath && targetPath !== window.location.pathname;
|
|
317
|
+
if (pushed) history.pushState(null, "", targetPath);
|
|
318
|
+
pushedRef.current = pushed;
|
|
319
|
+
sharePathRef.current = targetPath ?? window.location.pathname;
|
|
320
|
+
|
|
296
321
|
// The broker decides whether this tab owns the connection. `establish` is
|
|
297
322
|
// only invoked when we're the owner (or get promoted on failover); other
|
|
298
323
|
// tabs reuse the owner's channel via a proxy, so they never open WebRTC.
|
|
@@ -326,29 +351,31 @@ export function Discovery() {
|
|
|
326
351
|
await connBroker.connect(server.peerId, establish);
|
|
327
352
|
setConnState("connected");
|
|
328
353
|
// The daemon no longer sets a default folder (current VS Code serve-web
|
|
329
|
-
// dropped that flag), so open the served workspace from here:
|
|
354
|
+
// dropped that flag), so open the served workspace from here: the
|
|
330
355
|
// deep-link folder if we have one, else the server's reported cwd.
|
|
331
|
-
const openFolder = folder ?? server.meta?.cwd;
|
|
332
356
|
activeFolderRef.current = openFolder;
|
|
333
357
|
setIframeSrc(`/vs/${server.peerId}/${folderQuery(openFolder)}`);
|
|
334
358
|
setResolving(null);
|
|
335
359
|
recordConnect(server, room, openFolder);
|
|
336
|
-
|
|
360
|
+
viewingRef.current = true;
|
|
337
361
|
} catch {
|
|
338
362
|
setConnState("failed");
|
|
363
|
+
// Undo the optimistic history entry / URL change. We never started
|
|
364
|
+
// viewing, so the popstate handler leaves the "failed" card in place.
|
|
365
|
+
if (pushed) {
|
|
366
|
+
pushedRef.current = false;
|
|
367
|
+
history.back();
|
|
368
|
+
}
|
|
339
369
|
}
|
|
340
370
|
}
|
|
341
371
|
|
|
342
|
-
//
|
|
343
|
-
//
|
|
344
|
-
//
|
|
345
|
-
function
|
|
346
|
-
|
|
372
|
+
// Shareable deep-link pathname for a server+folder, with no side effects (no
|
|
373
|
+
// token — Share adds that). Keeps an existing deep-link path as-is; otherwise
|
|
374
|
+
// derives /gh|/git|/dev from the server's repo identity or opened folder.
|
|
375
|
+
function shareablePathFor(server: PeerInfo, folder?: string): string | null {
|
|
376
|
+
return deepLinkRef.current
|
|
347
377
|
? window.location.pathname
|
|
348
378
|
: shareableDeepLink({ repo: server.meta?.repo, branch: server.meta?.branch, folder });
|
|
349
|
-
if (!path) return;
|
|
350
|
-
sharePathRef.current = path;
|
|
351
|
-
if (path !== window.location.pathname) history.replaceState(null, "", path);
|
|
352
379
|
}
|
|
353
380
|
|
|
354
381
|
async function shareLink() {
|
|
@@ -408,7 +435,10 @@ export function Discovery() {
|
|
|
408
435
|
if (dl?.type === "repo") recordConnection(repoKey(dl.target), { ...base, folder });
|
|
409
436
|
}
|
|
410
437
|
|
|
411
|
-
|
|
438
|
+
// Tear down the active connection and return to the workspace list. Does NOT
|
|
439
|
+
// touch history — the caller (Disconnect → history.back, or a popstate from
|
|
440
|
+
// Cmd+Left) owns the URL.
|
|
441
|
+
function teardownConn() {
|
|
412
442
|
rtcRef.current?.close();
|
|
413
443
|
rtcRef.current = null;
|
|
414
444
|
if (activePeerRef.current) connBroker.disconnect(activePeerRef.current);
|
|
@@ -418,6 +448,18 @@ export function Discovery() {
|
|
|
418
448
|
activeRoomRef.current = null;
|
|
419
449
|
setConnState("idle");
|
|
420
450
|
sharePathRef.current = null;
|
|
451
|
+
pushedRef.current = false;
|
|
452
|
+
viewingRef.current = false;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function disconnect() {
|
|
456
|
+
// Mirror Cmd+Left: if connecting pushed a history entry, pop it — the
|
|
457
|
+
// browser restores the previous URL and our popstate handler tears down.
|
|
458
|
+
if (pushedRef.current) {
|
|
459
|
+
history.back();
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
teardownConn();
|
|
421
463
|
if (window.location.pathname !== "/") history.replaceState(null, "", "/");
|
|
422
464
|
}
|
|
423
465
|
|