fix: interrupt scaffold drain and desktop CLI bin layout
This commit is contained in:
@@ -158,6 +158,8 @@ function buildDesktopDaemonCorsOriginsEnv(): string | undefined {
|
||||
.filter((value) => value.length > 0)
|
||||
);
|
||||
|
||||
origins.add("paseo://app");
|
||||
|
||||
const devServerUrl = process.env.EXPO_DEV_URL ?? DEFAULT_ELECTRON_DEV_SERVER_URL;
|
||||
try {
|
||||
const parsed = new URL(devServerUrl);
|
||||
@@ -479,7 +481,7 @@ function getCliSymlinkInstructions(): CliSymlinkInstructions {
|
||||
|
||||
if (process.platform === "darwin") {
|
||||
const appBundle = electronExePath.replace(/\/Contents\/MacOS\/.+$/, "");
|
||||
const cliPath = path.join(appBundle, "Contents", "MacOS", cliShimFilename);
|
||||
const cliPath = path.join(appBundle, "Contents", "Resources", "bin", cliShimFilename);
|
||||
return {
|
||||
title: "Add paseo to your shell",
|
||||
detail: "Create a symlink to the bundled Paseo CLI shim.",
|
||||
@@ -488,18 +490,20 @@ function getCliSymlinkInstructions(): CliSymlinkInstructions {
|
||||
}
|
||||
|
||||
if (process.platform === "win32") {
|
||||
const cliPath = path.join(path.dirname(electronExePath), "resources", "bin", cliShimFilename);
|
||||
return {
|
||||
title: "Add paseo to your PATH",
|
||||
detail: "Add the Paseo installation directory to your system PATH so paseo.cmd is available.",
|
||||
commands: `setx PATH "%PATH%;${path.dirname(electronExePath)}"`,
|
||||
commands: `setx PATH "%PATH%;${path.dirname(cliPath)}"`,
|
||||
};
|
||||
}
|
||||
|
||||
// Linux
|
||||
const cliPath = path.join(path.dirname(electronExePath), "resources", "bin", cliShimFilename);
|
||||
return {
|
||||
title: "Add paseo to your shell",
|
||||
detail: "Create a symlink to the bundled Paseo CLI shim.",
|
||||
commands: `sudo ln -sf "${path.join(path.dirname(electronExePath), cliShimFilename)}" /usr/local/bin/paseo`,
|
||||
commands: `sudo ln -sf "${cliPath}" /usr/local/bin/paseo`,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import path from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { existsSync } from "node:fs";
|
||||
import { app, BrowserWindow, nativeImage } from "electron";
|
||||
import { app, BrowserWindow, nativeImage, net, protocol } from "electron";
|
||||
import { registerDaemonManager } from "./daemon/daemon-manager.js";
|
||||
import { parseCliPassthroughArgsFromArgv, runCliPassthroughCommand } from "./daemon/runtime-paths.js";
|
||||
import { closeAllTransportSessions } from "./daemon/local-transport.js";
|
||||
@@ -11,8 +12,13 @@ import { registerOpenerHandlers } from "./features/opener.js";
|
||||
import { setupApplicationMenu } from "./features/menu.js";
|
||||
|
||||
const DEV_SERVER_URL = process.env.EXPO_DEV_URL ?? "http://localhost:8081";
|
||||
const APP_SCHEME = "paseo";
|
||||
app.setName("Paseo");
|
||||
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{ scheme: APP_SCHEME, privileges: { standard: true, secure: true, supportFetchAPI: true } },
|
||||
]);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Window creation
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -21,12 +27,12 @@ function getPreloadPath(): string {
|
||||
return path.join(__dirname, "preload.js");
|
||||
}
|
||||
|
||||
function getProductionEntryPath(): string {
|
||||
function getAppDistDir(): string {
|
||||
if (app.isPackaged) {
|
||||
return path.join(process.resourcesPath, "app-dist", "index.html");
|
||||
return path.join(process.resourcesPath, "app-dist");
|
||||
}
|
||||
|
||||
return path.resolve(__dirname, "../../app/dist/index.html");
|
||||
return path.resolve(__dirname, "../../app/dist");
|
||||
}
|
||||
|
||||
function getWindowIconPath(): string | null {
|
||||
@@ -94,7 +100,7 @@ async function createMainWindow(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
await mainWindow.loadFile(getProductionEntryPath());
|
||||
await mainWindow.loadURL(`${APP_SCHEME}://app/`);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -148,6 +154,34 @@ async function bootstrap(): Promise<void> {
|
||||
}
|
||||
|
||||
await app.whenReady();
|
||||
|
||||
const appDistDir = getAppDistDir();
|
||||
protocol.handle(APP_SCHEME, (request) => {
|
||||
const { pathname, search, hash } = new URL(request.url);
|
||||
const decodedPath = decodeURIComponent(pathname);
|
||||
|
||||
// Chromium can occasionally request the exported entrypoint directly.
|
||||
// Canonicalize it back to the route URL so Expo Router sees `/`, not `/index.html`.
|
||||
if (decodedPath.endsWith("/index.html")) {
|
||||
const normalizedPath = decodedPath.slice(0, -"/index.html".length) || "/";
|
||||
return Response.redirect(`${APP_SCHEME}://app${normalizedPath}${search}${hash}`, 307);
|
||||
}
|
||||
|
||||
const filePath = path.join(appDistDir, decodedPath);
|
||||
const relativePath = path.relative(appDistDir, filePath);
|
||||
|
||||
if (relativePath.startsWith("..") || path.isAbsolute(relativePath)) {
|
||||
return new Response("Not found", { status: 404 });
|
||||
}
|
||||
|
||||
// SPA fallback: serve index.html for routes without a file extension
|
||||
if (!relativePath || !path.extname(relativePath)) {
|
||||
return net.fetch(pathToFileURL(path.join(appDistDir, "index.html")).toString());
|
||||
}
|
||||
|
||||
return net.fetch(pathToFileURL(filePath).toString());
|
||||
});
|
||||
|
||||
applyAppIcon();
|
||||
setupApplicationMenu();
|
||||
ensureNotificationCenterRegistration();
|
||||
|
||||
Reference in New Issue
Block a user