产品化改造:完善本地集成与启动体验

This commit is contained in:
baiyanyun
2026-06-02 17:55:08 +08:00
parent a280774f50
commit 873cd6ef53
24 changed files with 3490 additions and 45 deletions

View File

@@ -486,13 +486,15 @@ function App() {
const deps = result?.results ?? [];
const hasMissingOrError = deps.some(
(d: { status: string }) =>
d.status === "missing" || d.status === "error",
(d: { status: string; required?: boolean }) =>
d.required !== false &&
(d.status === "missing" || d.status === "error"),
);
const missingDeps = deps
.filter(
(d: { status: string }) =>
d.status === "missing" || d.status === "error",
(d: { status: string; required?: boolean }) =>
d.required !== false &&
(d.status === "missing" || d.status === "error"),
)
.map((d: { name: string; status: string }) => d.name);

View File

@@ -20,6 +20,7 @@ import {
syncCookieAndGetNewSessionUrl,
syncCookieAndGetChatUrl,
persistTicketCookie,
normalizeLocalBackendRedirect,
} from "../../services/utils/sessionUrl";
import { logger } from "../../services/utils/logService";
import { APP_DISPLAY_NAME } from "@shared/constants";
@@ -89,19 +90,47 @@ function SessionsPage({
}
};
const onWillRedirect = (e: any) => {
const normalizedUrl = normalizeLocalBackendRedirect(
e.newURL,
webviewUrl,
);
if (normalizedUrl) {
logger.warn(
"[SessionsPage][WebviewNav] normalized local backend redirect",
"SessionsPage",
{
from: e.oldURL,
to: e.newURL,
normalizedUrl,
},
);
e.preventDefault?.();
el.loadURL?.(normalizedUrl);
return;
}
logger.info("[SessionsPage][WebviewNav] will-redirect", "SessionsPage", {
from: e.oldURL,
to: e.newURL,
});
};
const onDidFailLoad = (e: any) => {
logger.warn("[SessionsPage][WebviewNav] did-fail-load", "SessionsPage", {
url: e.validatedURL || e.url,
errorCode: e.errorCode,
errorDescription: e.errorDescription,
});
};
el.addEventListener("did-navigate", onDidNavigate);
el.addEventListener("did-navigate-in-page", onDidNavigate);
el.addEventListener("will-redirect", onWillRedirect);
el.addEventListener("did-fail-load", onDidFailLoad);
return () => {
el.removeEventListener("did-navigate", onDidNavigate);
el.removeEventListener("did-navigate-in-page", onDidNavigate);
el.removeEventListener("will-redirect", onWillRedirect);
el.removeEventListener("did-fail-load", onDidFailLoad);
};
}, [view, webviewUrl]); // eslint-disable-line react-hooks/exhaustive-deps

View File

@@ -3,6 +3,7 @@ import {
buildRedirectUrl,
buildNewSessionUrl,
buildChatSessionUrl,
normalizeLocalBackendRedirect,
syncSessionCookie,
syncCookieAndGetRedirectUrl,
syncCookieAndGetNewSessionUrl,
@@ -87,6 +88,51 @@ describe("buildChatSessionUrl", () => {
});
});
describe("normalizeLocalBackendRedirect", () => {
it("normalizes local redirects that lost protocol and port", () => {
expect(
normalizeLocalBackendRedirect(
"https://localhost/home/chat/5/26?hideMenu=true",
"http://localhost:18081/api/sandbox/config/redirect/6?hideMenu=true",
),
).toBe("http://localhost:18081/home/chat/5/26?hideMenu=true");
});
it("normalizes localhost and 127.0.0.1 mismatches to the configured backend", () => {
expect(
normalizeLocalBackendRedirect(
"https://localhost/home/chat/5/26?hideMenu=true",
"http://127.0.0.1:18081/api/sandbox/config/redirect/6?hideMenu=true",
),
).toBe("http://127.0.0.1:18081/home/chat/5/26?hideMenu=true");
});
it("does not rewrite already-correct local redirects", () => {
expect(
normalizeLocalBackendRedirect(
"http://localhost:18081/home/chat/5/26?hideMenu=true",
"http://localhost:18081/api/sandbox/config/redirect/6?hideMenu=true",
),
).toBeNull();
});
it("does not rewrite remote domains", () => {
expect(
normalizeLocalBackendRedirect(
"https://example.com/home/chat/5/26?hideMenu=true",
"https://example.com/api/sandbox/config/redirect/6?hideMenu=true",
),
).toBeNull();
});
it("returns null for invalid URLs", () => {
expect(normalizeLocalBackendRedirect("not-url", "http://localhost:18081"))
.toBeNull();
expect(normalizeLocalBackendRedirect("https://localhost", "not-url"))
.toBeNull();
});
});
describe("syncSessionCookie", () => {
it("不设 domain 和 secure由主进程根据 URL scheme 判断", async () => {
await syncSessionCookie("https://app.example.com:8080/path", "tok123");

View File

@@ -66,6 +66,46 @@ export function buildChatSessionUrl(domain: string, sessionId: string): string {
return `${normalizedDomain}/api/sandbox/config/redirect/chat/${sessionId}?hideMenu=true`;
}
function isLocalBackendHost(hostname: string): boolean {
return hostname === "localhost" || hostname === "127.0.0.1";
}
/**
* Some local backend builds redirect `http://localhost:18081/...` to
* `https://localhost/...`, losing both the protocol and port. Normalize only
* that local-only case so embedded webviews keep using the configured backend.
*/
export function normalizeLocalBackendRedirect(
redirectUrl: string,
expectedBackendUrl: string,
): string | null {
try {
const redirect = new URL(redirectUrl);
const expected = new URL(expectedBackendUrl);
if (
!isLocalBackendHost(expected.hostname) ||
!isLocalBackendHost(redirect.hostname)
) {
return null;
}
if (
redirect.protocol === expected.protocol &&
redirect.port === expected.port
) {
return null;
}
redirect.protocol = expected.protocol;
redirect.host = expected.host;
const normalized = redirect.toString();
return normalized === redirectUrl ? null : normalized;
} catch {
return null;
}
}
export async function syncSessionCookie(
domain: string,
token: string,