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:
@@ -1,13 +1,11 @@
|
|||||||
import { mkdir, mkdtemp, writeFile, rm } from "node:fs/promises";
|
import { mkdir, mkdtemp, writeFile, rm } from "node:fs/promises";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { pathToFileURL } from "node:url";
|
|
||||||
import { afterEach, describe, expect, test } from "vitest";
|
import { afterEach, describe, expect, test } from "vitest";
|
||||||
|
|
||||||
import { loadConfig, resolveBundledWebUiDistDir } from "./config.js";
|
import { loadConfig } from "./config.js";
|
||||||
|
|
||||||
const roots: string[] = [];
|
const roots: string[] = [];
|
||||||
|
|
||||||
async function createPaseoHome(config: unknown): Promise<string> {
|
async function createPaseoHome(config: unknown): Promise<string> {
|
||||||
const root = await mkdtemp(path.join(os.tmpdir(), "paseo-config-web-ui-"));
|
const root = await mkdtemp(path.join(os.tmpdir(), "paseo-config-web-ui-"));
|
||||||
roots.push(root);
|
roots.push(root);
|
||||||
@@ -49,24 +47,6 @@ describe("daemon web UI config", () => {
|
|||||||
expectBundledWebUiDistDir(config.webUi.distDir);
|
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 () => {
|
test("PASEO_WEB_UI_ENABLED overrides persisted setting", async () => {
|
||||||
const home = await createPaseoHome({
|
const home = await createPaseoHome({
|
||||||
version: 1,
|
version: 1,
|
||||||
|
|||||||
@@ -1,61 +1,63 @@
|
|||||||
|
import { mkdir, mkdtemp, rm } from "node:fs/promises";
|
||||||
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { pathToFileURL } from "node:url";
|
import { pathToFileURL } from "node:url";
|
||||||
import { describe, expect, test } from "vitest";
|
import { afterEach, describe, expect, test } from "vitest";
|
||||||
|
|
||||||
import { resolveBundledWebUiDistDir } from "./config.js";
|
import { resolveBundledWebUiDistDir } from "./config.js";
|
||||||
|
|
||||||
function fileUrlFor(...segments: string[]): URL {
|
const roots: string[] = [];
|
||||||
return pathToFileURL(path.join(path.parse(process.cwd()).root, ...segments));
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("server config", () => {
|
describe("server config", () => {
|
||||||
test("resolves bundled web UI path from source-tree modules", () => {
|
afterEach(async () => {
|
||||||
expect(
|
await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
|
||||||
resolveBundledWebUiDistDir(
|
|
||||||
fileUrlFor("repo", "packages", "server", "src", "server", "config.ts"),
|
|
||||||
),
|
|
||||||
).toBe(
|
|
||||||
path.join(
|
|
||||||
path.parse(process.cwd()).root,
|
|
||||||
"repo",
|
|
||||||
"packages",
|
|
||||||
"server",
|
|
||||||
"dist",
|
|
||||||
"server",
|
|
||||||
"web-ui",
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
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(
|
expect(
|
||||||
resolveBundledWebUiDistDir(
|
resolveBundledWebUiDistDir({
|
||||||
fileUrlFor(
|
moduleUrl: pathToFileURL(
|
||||||
"usr",
|
path.join(root, "repo", "packages", "server", "src", "server", "config.ts"),
|
||||||
"local",
|
|
||||||
"lib",
|
|
||||||
"node_modules",
|
|
||||||
"@getpaseo",
|
|
||||||
"server",
|
|
||||||
"dist",
|
|
||||||
"server",
|
|
||||||
"server",
|
|
||||||
"config.js",
|
|
||||||
),
|
),
|
||||||
),
|
}),
|
||||||
).toBe(
|
).toBe(path.join(root, "repo", "packages", "server", "dist", "server", "web-ui"));
|
||||||
path.join(
|
});
|
||||||
path.parse(process.cwd()).root,
|
|
||||||
"usr",
|
test("resolves bundled web UI path from globally installed compiled modules", async () => {
|
||||||
"local",
|
const packageRoot = await mkdtemp(path.join(os.tmpdir(), "paseo-config-compiled-"));
|
||||||
"lib",
|
roots.push(packageRoot);
|
||||||
"node_modules",
|
await mkdir(path.join(packageRoot, "dist", "server", "web-ui"), { recursive: true });
|
||||||
"@getpaseo",
|
|
||||||
"server",
|
expect(
|
||||||
"dist",
|
resolveBundledWebUiDistDir({
|
||||||
"server",
|
moduleUrl: pathToFileURL(path.join(packageRoot, "dist", "server", "server", "config.js")),
|
||||||
"web-ui",
|
}),
|
||||||
),
|
).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"));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { existsSync } from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
import { resolvePaseoNodeEnv } from "./paseo-env.js";
|
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_APP_BASE_URL = "https://app.paseo.sh";
|
||||||
const DEFAULT_TRUSTED_PROXIES = ["loopback"];
|
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));
|
const moduleDir = path.dirname(fileURLToPath(moduleUrl));
|
||||||
|
|
||||||
if (path.basename(moduleDir) === "server" && path.basename(path.dirname(moduleDir)) === "src") {
|
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(moduleDir)) === "server" &&
|
||||||
path.basename(path.dirname(path.dirname(moduleDir))) === "dist"
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
function parseBooleanEnv(value: string | undefined): boolean | undefined {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
|
|||||||
Reference in New Issue
Block a user