fix: interrupt scaffold drain and desktop CLI bin layout
This commit is contained in:
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
RESOURCES_DIR=$(CDPATH= cd -- "${SCRIPT_DIR}/.." && pwd)
|
||||
|
||||
# macOS: MacOS/Paseo is a sibling of Resources/
|
||||
# Linux: the executable sits next to resources/
|
||||
if [ -x "${RESOURCES_DIR}/../MacOS/Paseo" ]; then
|
||||
APP_EXECUTABLE="${RESOURCES_DIR}/../MacOS/Paseo"
|
||||
elif [ -x "${RESOURCES_DIR}/../Paseo" ]; then
|
||||
APP_EXECUTABLE="${RESOURCES_DIR}/../Paseo"
|
||||
else
|
||||
echo "Bundled Paseo executable not found relative to ${RESOURCES_DIR}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CLI_ENTRY="${RESOURCES_DIR}/app.asar/node_modules/@getpaseo/cli/dist/index.js"
|
||||
|
||||
exec env ELECTRON_RUN_AS_NODE=1 "${APP_EXECUTABLE}" "${CLI_ENTRY}" "$@"
|
||||
@@ -0,0 +1,15 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
set "SCRIPT_DIR=%~dp0"
|
||||
set "RESOURCES_DIR=%SCRIPT_DIR%.."
|
||||
set "APP_EXECUTABLE=%RESOURCES_DIR%\..\Paseo.exe"
|
||||
set "CLI_ENTRY=%RESOURCES_DIR%\app.asar\node_modules\@getpaseo\cli\dist\index.js"
|
||||
|
||||
if not exist "%APP_EXECUTABLE%" (
|
||||
echo Bundled Paseo executable not found at %APP_EXECUTABLE% 1>&2
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
set "ELECTRON_RUN_AS_NODE=1"
|
||||
"%APP_EXECUTABLE%" "%CLI_ENTRY%" %*
|
||||
@@ -19,26 +19,26 @@ mac:
|
||||
notarize: true
|
||||
entitlements: build/entitlements.mac.plist
|
||||
entitlementsInherit: build/entitlements.mac.inherit.plist
|
||||
extraFiles:
|
||||
- from: scripts/paseo
|
||||
to: MacOS/paseo
|
||||
extraResources:
|
||||
- from: bin/paseo
|
||||
to: bin/paseo
|
||||
target:
|
||||
- dmg
|
||||
- zip
|
||||
linux:
|
||||
category: Development
|
||||
icon: assets
|
||||
extraFiles:
|
||||
- from: scripts/paseo
|
||||
to: paseo
|
||||
extraResources:
|
||||
- from: bin/paseo
|
||||
to: bin/paseo
|
||||
target:
|
||||
- AppImage
|
||||
- tar.gz
|
||||
win:
|
||||
icon: assets/icon.ico
|
||||
extraFiles:
|
||||
- from: scripts/paseo.cmd
|
||||
to: paseo.cmd
|
||||
extraResources:
|
||||
- from: bin/paseo.cmd
|
||||
to: bin/paseo.cmd
|
||||
target:
|
||||
- nsis
|
||||
- zip
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
APP_EXECUTABLE="${SCRIPT_DIR}/Paseo"
|
||||
|
||||
if [ -d "${SCRIPT_DIR}/../Resources" ]; then
|
||||
RESOURCES_DIR="${SCRIPT_DIR}/../Resources"
|
||||
elif [ -d "${SCRIPT_DIR}/resources" ]; then
|
||||
RESOURCES_DIR="${SCRIPT_DIR}/resources"
|
||||
else
|
||||
echo "Unable to locate Paseo resources directory next to ${SCRIPT_DIR}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CLI_ENTRY="${RESOURCES_DIR}/app.asar/node_modules/@getpaseo/cli/dist/index.js"
|
||||
|
||||
if [ ! -x "${APP_EXECUTABLE}" ]; then
|
||||
echo "Bundled Paseo executable not found at ${APP_EXECUTABLE}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "${CLI_ENTRY}" ]; then
|
||||
echo "Bundled Paseo CLI entrypoint not found at ${CLI_ENTRY}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec env ELECTRON_RUN_AS_NODE=1 "${APP_EXECUTABLE}" "${CLI_ENTRY}" "$@"
|
||||
@@ -1,19 +0,0 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
set "SCRIPT_DIR=%~dp0"
|
||||
set "APP_EXECUTABLE=%SCRIPT_DIR%Paseo.exe"
|
||||
set "CLI_ENTRY=%SCRIPT_DIR%resources\app.asar\node_modules\@getpaseo\cli\dist\index.js"
|
||||
|
||||
if not exist "%APP_EXECUTABLE%" (
|
||||
echo Bundled Paseo executable not found at %APP_EXECUTABLE% 1>&2
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if not exist "%CLI_ENTRY%" (
|
||||
echo Bundled Paseo CLI entrypoint not found at %CLI_ENTRY% 1>&2
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
set "ELECTRON_RUN_AS_NODE=1"
|
||||
"%APP_EXECUTABLE%" "%CLI_ENTRY%" %*
|
||||
@@ -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