Fix default bundled web UI path in packaged desktop CLI (#1899)

* Fix packaged web UI dist dir resolution

* Fix bundled web UI path typecheck

* Fix packaged web UI path matcher

* Remove duplicate packaged web UI clause

* Merge packaged web UI path branch

* Use bundled web UI artifact existence

* Inline bundled web UI existence checks

* Restore original web UI fallback branch

* Reuse app-dist path in web UI resolver

* Format web UI resolver tests and config

* Tidy web UI resolver follow-up

* fix(server): tighten bundled web UI path resolution

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
This commit is contained in:
yz
2026-07-06 22:24:02 +08:00
committed by GitHub
parent 08a0d0c28d
commit d318629121
3 changed files with 69 additions and 71 deletions

View File

@@ -1,13 +1,11 @@
import { mkdir, mkdtemp, writeFile, rm } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { afterEach, describe, expect, test } from "vitest";
import { loadConfig, resolveBundledWebUiDistDir } from "./config.js";
import { loadConfig } from "./config.js";
const roots: string[] = [];
async function createPaseoHome(config: unknown): Promise<string> {
const root = await mkdtemp(path.join(os.tmpdir(), "paseo-config-web-ui-"));
roots.push(root);
@@ -49,24 +47,6 @@ describe("daemon web UI config", () => {
expectBundledWebUiDistDir(config.webUi.distDir);
});
test("resolves bundled web UI dist dir from TypeScript source modules", () => {
const packageRoot = path.join(os.tmpdir(), "paseo-config-web-ui-source-package");
const moduleUrl = pathToFileURL(path.join(packageRoot, "src", "server", "config.ts"));
expect(resolveBundledWebUiDistDir(moduleUrl)).toBe(
path.join(packageRoot, "dist", "server", "web-ui"),
);
});
test("resolves bundled web UI dist dir from compiled server modules", () => {
const packageRoot = path.join(os.tmpdir(), "paseo-config-web-ui-dist-package");
const moduleUrl = pathToFileURL(path.join(packageRoot, "dist", "server", "config.js"));
expect(resolveBundledWebUiDistDir(moduleUrl)).toBe(
path.join(packageRoot, "dist", "server", "web-ui"),
);
});
test("PASEO_WEB_UI_ENABLED overrides persisted setting", async () => {
const home = await createPaseoHome({
version: 1,

View File

@@ -1,61 +1,63 @@
import { mkdir, mkdtemp, rm } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { describe, expect, test } from "vitest";
import { afterEach, describe, expect, test } from "vitest";
import { resolveBundledWebUiDistDir } from "./config.js";
function fileUrlFor(...segments: string[]): URL {
return pathToFileURL(path.join(path.parse(process.cwd()).root, ...segments));
}
const roots: string[] = [];
describe("server config", () => {
test("resolves bundled web UI path from source-tree modules", () => {
expect(
resolveBundledWebUiDistDir(
fileUrlFor("repo", "packages", "server", "src", "server", "config.ts"),
),
).toBe(
path.join(
path.parse(process.cwd()).root,
"repo",
"packages",
"server",
"dist",
"server",
"web-ui",
),
);
afterEach(async () => {
await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
});
test("resolves bundled web UI path from globally installed compiled modules", () => {
test("resolves bundled web UI path from source-tree modules", () => {
const root = path.parse(process.cwd()).root;
expect(
resolveBundledWebUiDistDir(
fileUrlFor(
"usr",
"local",
"lib",
"node_modules",
"@getpaseo",
"server",
"dist",
"server",
"server",
"config.js",
resolveBundledWebUiDistDir({
moduleUrl: pathToFileURL(
path.join(root, "repo", "packages", "server", "src", "server", "config.ts"),
),
),
).toBe(
path.join(
path.parse(process.cwd()).root,
"usr",
"local",
"lib",
"node_modules",
"@getpaseo",
"server",
"dist",
"server",
"web-ui",
),
);
}),
).toBe(path.join(root, "repo", "packages", "server", "dist", "server", "web-ui"));
});
test("resolves bundled web UI path from globally installed compiled modules", async () => {
const packageRoot = await mkdtemp(path.join(os.tmpdir(), "paseo-config-compiled-"));
roots.push(packageRoot);
await mkdir(path.join(packageRoot, "dist", "server", "web-ui"), { recursive: true });
expect(
resolveBundledWebUiDistDir({
moduleUrl: pathToFileURL(path.join(packageRoot, "dist", "server", "server", "config.js")),
}),
).toBe(path.join(packageRoot, "dist", "server", "web-ui"));
});
test("resolves packaged desktop web UI path from resources app-dist", async () => {
const packageRoot = await mkdtemp(path.join(os.tmpdir(), "paseo-config-packaged-"));
roots.push(packageRoot);
await mkdir(path.join(packageRoot, "app-dist"), { recursive: true });
expect(
resolveBundledWebUiDistDir({
moduleUrl: pathToFileURL(
path.join(
packageRoot,
"app.asar",
"node_modules",
"@getpaseo",
"server",
"dist",
"server",
"server",
"config.js",
),
),
resourcesPath: packageRoot,
}),
).toBe(path.join(packageRoot, "app-dist"));
});
});

View File

@@ -1,3 +1,4 @@
import { existsSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { resolvePaseoNodeEnv } from "./paseo-env.js";
@@ -27,7 +28,13 @@ const DEFAULT_RELAY_ENDPOINT = "relay.paseo.sh:443";
const DEFAULT_APP_BASE_URL = "https://app.paseo.sh";
const DEFAULT_TRUSTED_PROXIES = ["loopback"];
export function resolveBundledWebUiDistDir(moduleUrl: string | URL = import.meta.url): string {
interface ResolveBundledWebUiDistDirInput {
moduleUrl?: string | URL;
resourcesPath?: string;
}
export function resolveBundledWebUiDistDir(input: ResolveBundledWebUiDistDirInput = {}): string {
const moduleUrl = input.moduleUrl ?? import.meta.url;
const moduleDir = path.dirname(fileURLToPath(moduleUrl));
if (path.basename(moduleDir) === "server" && path.basename(path.dirname(moduleDir)) === "src") {
@@ -39,13 +46,22 @@ export function resolveBundledWebUiDistDir(moduleUrl: string | URL = import.meta
path.basename(path.dirname(moduleDir)) === "server" &&
path.basename(path.dirname(path.dirname(moduleDir))) === "dist"
) {
const appDistDir = input.resourcesPath ? path.join(input.resourcesPath, "app-dist") : null;
if (appDistDir && existsSync(appDistDir)) {
return appDistDir;
}
return path.resolve(moduleDir, "..", "web-ui");
}
return path.resolve(moduleDir, "web-ui");
}
const BUNDLED_WEB_UI_DIST_DIR = resolveBundledWebUiDistDir();
const processResourcesPath = "resourcesPath" in process ? process.resourcesPath : undefined;
const BUNDLED_WEB_UI_DIST_DIR = resolveBundledWebUiDistDir({
resourcesPath: typeof processResourcesPath === "string" ? processResourcesPath : undefined,
});
function parseBooleanEnv(value: string | undefined): boolean | undefined {
if (value === undefined) {