fix(desktop): Workspace HTML previews (render view and new window) (#189)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d312d368b8
commit
e015d9e591
7 files changed
+108
-4
No files matched your search
@@ -20,6 +20,12 @@ export interface ServerConfig {
|
||||
root: string;
|
||||
/** HTTP listen address and port (defaults to 127.0.0.1:7364, deliberately avoiding common ports like 3000/8080). */
|
||||
host: string;
|
||||
/**
|
||||
* Listen port. `0` asks the OS for an ephemeral port (the desktop shell always does),
|
||||
* in which case the value is only a request: index.ts writes the ACTUAL bound port back
|
||||
* here once listening, because preview URLs are built from the server's own port rather
|
||||
* than the browser's (dev serves the SPA on a different port; see resolvePreviewTarget).
|
||||
*/
|
||||
port: number;
|
||||
/** SQLite database path; ":memory:" for test injection. */
|
||||
dbPath: string;
|
||||
|
||||
@@ -96,6 +96,12 @@ const server = serve({ fetch: app.fetch, hostname: config.host, port: config.por
|
||||
console.log(`Data root: ${config.root}`);
|
||||
console.log(`SQLite: ${config.dbPath}`);
|
||||
if (config.desktopToken !== null) console.log("Desktop mode: enabled");
|
||||
// PORT=0 asked for an ephemeral port: record the real one so everything derived from
|
||||
// the server's own port is correct — Workspace preview URLs above all, which are built
|
||||
// from the bind port on purpose (see resolvePreviewTarget) and would otherwise point at
|
||||
// port 0 and fail to load. deps.config is this same object, so both route call sites
|
||||
// (me.ts, sessions.ts) observe the update.
|
||||
config.port = info.port;
|
||||
// The root exists by now (openDatabase created it), and the pre-start check found no
|
||||
// live owner — record ourselves as this root's server.
|
||||
acquireServerLock(config.root, {
|
||||
|
||||
@@ -189,6 +189,12 @@ export function resolvePreviewTarget(
|
||||
const counterpart = loopbackCounterpart(requestHost);
|
||||
if (!counterpart) return null;
|
||||
if (!loopbackHostRoles(serverBind.host)) return null;
|
||||
// Port 0 means "the listener has not reported its actual port yet" (PORT=0 picks an
|
||||
// ephemeral one; index.ts writes it back once bound). Emitting `:0` would produce a URL
|
||||
// no browser will load — Chromium rejects it outright with ERR_UNSAFE_PORT — so degrade
|
||||
// to "no isolated preview" instead, which the UI already handles by falling back to the
|
||||
// sandboxed same-origin preview.
|
||||
if (serverBind.port === 0) return null;
|
||||
|
||||
let protocol: string;
|
||||
try {
|
||||
|
||||
@@ -96,6 +96,15 @@ describe("preview origin derivation", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("gives up while the bind port is still 0, rather than emitting an unloadable :0 URL", () => {
|
||||
// PORT=0 (the desktop shell) before index.ts writes the actual port back: a `:0` URL
|
||||
// is rejected by Chromium as ERR_UNSAFE_PORT, so previewIsolated reports false and the
|
||||
// UI falls back to the sandboxed same-origin preview.
|
||||
expect(
|
||||
resolvePreviewTarget("http://localhost:0/x", "localhost:0", null, { ...bind, port: 0 }),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it("gives up when the loopback counterpart is not reachable from the bind address", () => {
|
||||
expect(
|
||||
resolvePreviewTarget("http://localhost:7364/x", "localhost:7364", null, {
|
||||
|
||||
Reference in new issue
Block a user