fix(desktop): harden packaged launcher and desktop build
This commit is contained in:
+1
-1
@@ -14,7 +14,7 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "./scripts/dev.sh",
|
"dev": "./scripts/dev.sh",
|
||||||
"dev:server": "NODE_ENV=development tsx packages/server/scripts/daemon-runner.ts --dev",
|
"dev:server": "npm run dev --workspace=@getpaseo/server",
|
||||||
"dev:app": "npm run start --workspace=@getpaseo/app",
|
"dev:app": "npm run start --workspace=@getpaseo/app",
|
||||||
"dev:website": "npm run dev --workspace=@getpaseo/website",
|
"dev:website": "npm run dev --workspace=@getpaseo/website",
|
||||||
"postinstall": "node scripts/postinstall-patches.mjs",
|
"postinstall": "node scripts/postinstall-patches.mjs",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "expo start",
|
"start": "expo start",
|
||||||
"reset-project": "node ./scripts/reset-project.js",
|
"reset-project": "node ./scripts/reset-project.js",
|
||||||
"build:workspace-deps": "npm run build --workspace=@getpaseo/highlight && npm run build --prefix ../expo-two-way-audio",
|
"build:workspace-deps": "npm run build --workspace=@getpaseo/highlight && npm run build --workspace=@getpaseo/expo-two-way-audio",
|
||||||
"eas-build-post-install": "npm run build:workspace-deps",
|
"eas-build-post-install": "npm run build:workspace-deps",
|
||||||
"android": "npm run android:development",
|
"android": "npm run android:development",
|
||||||
"android:development": "APP_VARIANT=development expo prebuild --platform android --non-interactive && APP_VARIANT=development expo run:android --variant=debug",
|
"android:development": "APP_VARIANT=development expo prebuild --platform android --non-interactive && APP_VARIANT=development expo run:android --variant=debug",
|
||||||
|
|||||||
@@ -1,7 +1,23 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
SCRIPT_PATH=$0
|
||||||
|
case "$SCRIPT_PATH" in
|
||||||
|
/*) ;;
|
||||||
|
*) SCRIPT_PATH="$(pwd)/$SCRIPT_PATH" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Follow symlinks so `/usr/local/bin/paseo` resolves back into the app bundle.
|
||||||
|
while [ -L "$SCRIPT_PATH" ]; do
|
||||||
|
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$SCRIPT_PATH")" && pwd)
|
||||||
|
LINK_TARGET=$(readlink "$SCRIPT_PATH")
|
||||||
|
case "$LINK_TARGET" in
|
||||||
|
/*) SCRIPT_PATH="$LINK_TARGET" ;;
|
||||||
|
*) SCRIPT_PATH="${SCRIPT_DIR}/${LINK_TARGET}" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$SCRIPT_PATH")" && pwd)
|
||||||
RESOURCES_DIR=$(CDPATH= cd -- "${SCRIPT_DIR}/.." && pwd)
|
RESOURCES_DIR=$(CDPATH= cd -- "${SCRIPT_DIR}/.." && pwd)
|
||||||
|
|
||||||
# macOS: MacOS/Paseo is a sibling of Resources/
|
# macOS: MacOS/Paseo is a sibling of Resources/
|
||||||
@@ -15,6 +31,4 @@ else
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
CLI_ENTRY="${RESOURCES_DIR}/app.asar/node_modules/@getpaseo/cli/dist/index.js"
|
exec env PASEO_DESKTOP_CLI=1 "${APP_EXECUTABLE}" "$@"
|
||||||
|
|
||||||
exec env ELECTRON_RUN_AS_NODE=1 "${APP_EXECUTABLE}" "${CLI_ENTRY}" "$@"
|
|
||||||
|
|||||||
@@ -4,12 +4,10 @@ setlocal
|
|||||||
set "SCRIPT_DIR=%~dp0"
|
set "SCRIPT_DIR=%~dp0"
|
||||||
set "RESOURCES_DIR=%SCRIPT_DIR%.."
|
set "RESOURCES_DIR=%SCRIPT_DIR%.."
|
||||||
set "APP_EXECUTABLE=%RESOURCES_DIR%\..\Paseo.exe"
|
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%" (
|
if not exist "%APP_EXECUTABLE%" (
|
||||||
echo Bundled Paseo executable not found at %APP_EXECUTABLE% 1>&2
|
echo Bundled Paseo executable not found at %APP_EXECUTABLE% 1>&2
|
||||||
exit /b 1
|
exit /b 1
|
||||||
)
|
)
|
||||||
|
|
||||||
set "ELECTRON_RUN_AS_NODE=1"
|
set "PASEO_DESKTOP_CLI=1"
|
||||||
"%APP_EXECUTABLE%" "%CLI_ENTRY%" %*
|
"%APP_EXECUTABLE%" %*
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
"build": "npm --prefix ../.. run build:daemon && npm run build:main && electron-builder --config electron-builder.yml",
|
"build": "npm --prefix ../.. run build:daemon && npm run build:main && electron-builder --config electron-builder.yml",
|
||||||
"build:main": "tsc -p tsconfig.json",
|
"build:main": "tsc -p tsconfig.json",
|
||||||
"dev": "npm run build:main && wait-on tcp:8081 && electron .",
|
"dev": "npm run build:main && wait-on tcp:8081 && electron .",
|
||||||
|
"test": "vitest run",
|
||||||
"typecheck": "tsc --noEmit -p tsconfig.json"
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import {
|
|||||||
sendLocalTransportMessage,
|
sendLocalTransportMessage,
|
||||||
closeLocalTransportSession,
|
closeLocalTransportSession,
|
||||||
} from "./local-transport.js";
|
} from "./local-transport.js";
|
||||||
import { createElectronNodeEnv, resolveDaemonRunnerEntrypoint } from "./runtime-paths.js";
|
import { createNodeEntrypointInvocation, resolveDaemonRunnerEntrypoint } from "./runtime-paths.js";
|
||||||
|
|
||||||
const DAEMON_LOG_FILENAME = "daemon.log";
|
const DAEMON_LOG_FILENAME = "daemon.log";
|
||||||
const DAEMON_PID_FILENAME = "paseo.pid";
|
const DAEMON_PID_FILENAME = "paseo.pid";
|
||||||
@@ -293,17 +293,23 @@ async function startDaemon(): Promise<DesktopDaemonStatus> {
|
|||||||
const home = getPaseoHome();
|
const home = getPaseoHome();
|
||||||
const daemonRunner = resolveDaemonRunnerEntrypoint();
|
const daemonRunner = resolveDaemonRunnerEntrypoint();
|
||||||
const corsOrigins = buildDesktopDaemonCorsOriginsEnv();
|
const corsOrigins = buildDesktopDaemonCorsOriginsEnv();
|
||||||
|
const invocation = createNodeEntrypointInvocation({
|
||||||
|
entrypoint: daemonRunner,
|
||||||
|
argvMode: "node-script",
|
||||||
|
args: [],
|
||||||
|
baseEnv: {
|
||||||
|
...process.env,
|
||||||
|
PASEO_HOME: home,
|
||||||
|
...(corsOrigins ? { PASEO_CORS_ORIGINS: corsOrigins } : {}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const child: ChildProcess = spawn(
|
const child: ChildProcess = spawn(
|
||||||
process.execPath,
|
invocation.command,
|
||||||
[...daemonRunner.execArgv, daemonRunner.entryPath],
|
invocation.args,
|
||||||
{
|
{
|
||||||
detached: true,
|
detached: true,
|
||||||
env: createElectronNodeEnv({
|
env: invocation.env,
|
||||||
...process.env,
|
|
||||||
PASEO_HOME: home,
|
|
||||||
...(corsOrigins ? { PASEO_CORS_ORIGINS: corsOrigins } : {}),
|
|
||||||
}),
|
|
||||||
stdio: ["ignore", "ignore", "ignore"],
|
stdio: ["ignore", "ignore", "ignore"],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,131 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import {
|
||||||
|
createNodeEntrypointInvocation,
|
||||||
|
parseCliPassthroughArgsFromArgv,
|
||||||
|
type NodeEntrypointSpec,
|
||||||
|
} from "./node-entrypoint-launcher";
|
||||||
|
|
||||||
|
const CLI_ENTRYPOINT: NodeEntrypointSpec = {
|
||||||
|
entryPath: "/tmp/paseo-cli.js",
|
||||||
|
execArgv: ["--import", "tsx"],
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("node-entrypoint-launcher", () => {
|
||||||
|
describe("parseCliPassthroughArgsFromArgv", () => {
|
||||||
|
it("returns null when no CLI args are provided", () => {
|
||||||
|
expect(
|
||||||
|
parseCliPassthroughArgsFromArgv({
|
||||||
|
argv: ["/Applications/Paseo.app/Contents/MacOS/Paseo"],
|
||||||
|
isDefaultApp: false,
|
||||||
|
forceCli: false,
|
||||||
|
}),
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ignores macOS GUI launch arguments", () => {
|
||||||
|
expect(
|
||||||
|
parseCliPassthroughArgsFromArgv({
|
||||||
|
argv: ["/Applications/Paseo.app/Contents/MacOS/Paseo", "-psn_0_12345"],
|
||||||
|
isDefaultApp: false,
|
||||||
|
forceCli: false,
|
||||||
|
}),
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("preserves CLI flags for direct app invocations", () => {
|
||||||
|
expect(
|
||||||
|
parseCliPassthroughArgsFromArgv({
|
||||||
|
argv: ["/Applications/Paseo.app/Contents/MacOS/Paseo", "--version"],
|
||||||
|
isDefaultApp: false,
|
||||||
|
forceCli: false,
|
||||||
|
}),
|
||||||
|
).toEqual(["--version"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("forces CLI mode for shim launches even without args", () => {
|
||||||
|
expect(
|
||||||
|
parseCliPassthroughArgsFromArgv({
|
||||||
|
argv: ["/Applications/Paseo.app/Contents/MacOS/Paseo"],
|
||||||
|
isDefaultApp: false,
|
||||||
|
forceCli: true,
|
||||||
|
}),
|
||||||
|
).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("createNodeEntrypointInvocation", () => {
|
||||||
|
it("uses the packaged runner when the desktop app is packaged", () => {
|
||||||
|
expect(
|
||||||
|
createNodeEntrypointInvocation({
|
||||||
|
execPath: "/Applications/Paseo.app/Contents/MacOS/Paseo",
|
||||||
|
isPackaged: true,
|
||||||
|
packagedRunnerPath: "/Applications/Paseo.app/Contents/Resources/app.asar/dist/daemon/node-entrypoint-runner.js",
|
||||||
|
entrypoint: CLI_ENTRYPOINT,
|
||||||
|
argvMode: "bare",
|
||||||
|
args: ["ls", "--json"],
|
||||||
|
baseEnv: { PATH: "/usr/bin" },
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
command: "/Applications/Paseo.app/Contents/MacOS/Paseo",
|
||||||
|
args: [
|
||||||
|
"/Applications/Paseo.app/Contents/Resources/app.asar/dist/daemon/node-entrypoint-runner.js",
|
||||||
|
"bare",
|
||||||
|
"/tmp/paseo-cli.js",
|
||||||
|
"ls",
|
||||||
|
"--json",
|
||||||
|
],
|
||||||
|
env: {
|
||||||
|
PATH: "/usr/bin",
|
||||||
|
ELECTRON_RUN_AS_NODE: "1",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses the entrypoint directly in development", () => {
|
||||||
|
expect(
|
||||||
|
createNodeEntrypointInvocation({
|
||||||
|
execPath: "/opt/homebrew/bin/electron",
|
||||||
|
isPackaged: false,
|
||||||
|
packagedRunnerPath: null,
|
||||||
|
entrypoint: CLI_ENTRYPOINT,
|
||||||
|
argvMode: "bare",
|
||||||
|
args: ["ls"],
|
||||||
|
baseEnv: { PATH: "/usr/bin" },
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
command: "/opt/homebrew/bin/electron",
|
||||||
|
args: ["--import", "tsx", "/tmp/paseo-cli.js", "ls"],
|
||||||
|
env: {
|
||||||
|
PATH: "/usr/bin",
|
||||||
|
ELECTRON_RUN_AS_NODE: "1",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps node-style argv for packaged script entrypoints", () => {
|
||||||
|
expect(
|
||||||
|
createNodeEntrypointInvocation({
|
||||||
|
execPath: "/Applications/Paseo.app/Contents/MacOS/Paseo",
|
||||||
|
isPackaged: true,
|
||||||
|
packagedRunnerPath: "/Applications/Paseo.app/Contents/Resources/app.asar/dist/daemon/node-entrypoint-runner.js",
|
||||||
|
entrypoint: CLI_ENTRYPOINT,
|
||||||
|
argvMode: "node-script",
|
||||||
|
args: ["--dev"],
|
||||||
|
baseEnv: { PATH: "/usr/bin" },
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
command: "/Applications/Paseo.app/Contents/MacOS/Paseo",
|
||||||
|
args: [
|
||||||
|
"/Applications/Paseo.app/Contents/Resources/app.asar/dist/daemon/node-entrypoint-runner.js",
|
||||||
|
"node-script",
|
||||||
|
"/tmp/paseo-cli.js",
|
||||||
|
"--dev",
|
||||||
|
],
|
||||||
|
env: {
|
||||||
|
PATH: "/usr/bin",
|
||||||
|
ELECTRON_RUN_AS_NODE: "1",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
const IGNORED_GUI_LAUNCH_ARG_PREFIX = "-psn_";
|
||||||
|
|
||||||
|
export const DESKTOP_CLI_ENV = "PASEO_DESKTOP_CLI";
|
||||||
|
|
||||||
|
export type NodeEntrypointSpec = {
|
||||||
|
entryPath: string;
|
||||||
|
execArgv: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NodeEntrypointInvocation = {
|
||||||
|
command: string;
|
||||||
|
args: string[];
|
||||||
|
env: NodeJS.ProcessEnv;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NodeEntrypointArgvMode = "bare" | "node-script";
|
||||||
|
|
||||||
|
type CreateNodeEntrypointInvocationInput = {
|
||||||
|
execPath: string;
|
||||||
|
isPackaged: boolean;
|
||||||
|
packagedRunnerPath: string | null;
|
||||||
|
entrypoint: NodeEntrypointSpec;
|
||||||
|
argvMode: NodeEntrypointArgvMode;
|
||||||
|
args: string[];
|
||||||
|
baseEnv: NodeJS.ProcessEnv;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ParseCliPassthroughArgsFromArgvInput = {
|
||||||
|
argv: string[];
|
||||||
|
isDefaultApp: boolean;
|
||||||
|
forceCli: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function createElectronNodeEnv(baseEnv: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
|
||||||
|
return {
|
||||||
|
...baseEnv,
|
||||||
|
ELECTRON_RUN_AS_NODE: "1",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseCliPassthroughArgsFromArgv(
|
||||||
|
input: ParseCliPassthroughArgsFromArgvInput,
|
||||||
|
): string[] | null {
|
||||||
|
const startIndex = input.isDefaultApp ? 2 : 1;
|
||||||
|
const effective = input.argv
|
||||||
|
.slice(startIndex)
|
||||||
|
.filter((arg) => !arg.startsWith(IGNORED_GUI_LAUNCH_ARG_PREFIX));
|
||||||
|
|
||||||
|
if (input.forceCli) {
|
||||||
|
return effective;
|
||||||
|
}
|
||||||
|
|
||||||
|
return effective.length > 0 ? effective : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createNodeEntrypointInvocation(
|
||||||
|
input: CreateNodeEntrypointInvocationInput,
|
||||||
|
): NodeEntrypointInvocation {
|
||||||
|
const env = createElectronNodeEnv(input.baseEnv);
|
||||||
|
|
||||||
|
if (input.isPackaged) {
|
||||||
|
if (!input.packagedRunnerPath) {
|
||||||
|
throw new Error("Packaged node entrypoint runner is required for desktop launches.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
command: input.execPath,
|
||||||
|
args: [input.packagedRunnerPath, input.argvMode, input.entrypoint.entryPath, ...input.args],
|
||||||
|
env,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
command: input.execPath,
|
||||||
|
args: [...input.entrypoint.execArgv, input.entrypoint.entryPath, ...input.args],
|
||||||
|
env,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { pathToFileURL } from "node:url";
|
||||||
|
|
||||||
|
async function main(): Promise<void> {
|
||||||
|
const [argvMode, entryPath, ...args] = process.argv.slice(2);
|
||||||
|
if (argvMode !== "bare" && argvMode !== "node-script") {
|
||||||
|
throw new Error(`Unsupported node entrypoint argv mode: ${argvMode ?? "<missing>"}`);
|
||||||
|
}
|
||||||
|
if (!entryPath) {
|
||||||
|
throw new Error("Missing node entrypoint path.");
|
||||||
|
}
|
||||||
|
|
||||||
|
process.argv =
|
||||||
|
argvMode === "bare" ? [process.argv[0] ?? "node", ...args] : [process.argv[0] ?? "node", entryPath, ...args];
|
||||||
|
await import(pathToFileURL(entryPath).href);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main().catch((error) => {
|
||||||
|
const message = error instanceof Error ? (error.stack ?? error.message) : String(error);
|
||||||
|
process.stderr.write(`${message}\n`);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
@@ -3,21 +3,23 @@ import { spawnSync, type SpawnSyncReturns } from "node:child_process";
|
|||||||
import { createRequire } from "node:module";
|
import { createRequire } from "node:module";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { app } from "electron";
|
import { app } from "electron";
|
||||||
|
import {
|
||||||
|
DESKTOP_CLI_ENV,
|
||||||
|
createNodeEntrypointInvocation as createSharedNodeEntrypointInvocation,
|
||||||
|
parseCliPassthroughArgsFromArgv as parseCliPassthroughArgs,
|
||||||
|
type NodeEntrypointArgvMode,
|
||||||
|
type NodeEntrypointInvocation,
|
||||||
|
type NodeEntrypointSpec,
|
||||||
|
} from "./node-entrypoint-launcher.js";
|
||||||
|
|
||||||
const CLI_PACKAGE_NAME = "@getpaseo/cli";
|
const CLI_PACKAGE_NAME = "@getpaseo/cli";
|
||||||
const SERVER_PACKAGE_NAME = "@getpaseo/server";
|
const SERVER_PACKAGE_NAME = "@getpaseo/server";
|
||||||
const CLI_BIN_ENTRY = `${CLI_PACKAGE_NAME}/bin/paseo`;
|
const CLI_BIN_ENTRY = `${CLI_PACKAGE_NAME}/bin/paseo`;
|
||||||
const IGNORED_GUI_LAUNCH_ARG_PREFIX = "-psn_";
|
|
||||||
|
|
||||||
type PackageInfo = {
|
type PackageInfo = {
|
||||||
root: string;
|
root: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type NodeEntrypointSpec = {
|
|
||||||
entryPath: string;
|
|
||||||
execArgv: string[];
|
|
||||||
};
|
|
||||||
|
|
||||||
const esmRequire = createRequire(__filename);
|
const esmRequire = createRequire(__filename);
|
||||||
|
|
||||||
function findPackageRootFromResolvedPath(input: {
|
function findPackageRootFromResolvedPath(input: {
|
||||||
@@ -73,6 +75,10 @@ function resolvePackagedAsarPath(): string {
|
|||||||
return path.join(process.resourcesPath, "app.asar");
|
return path.join(process.resourcesPath, "app.asar");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolvePackagedNodeEntrypointRunnerPath(): string {
|
||||||
|
return path.join(resolvePackagedAsarPath(), "dist", "daemon", "node-entrypoint-runner.js");
|
||||||
|
}
|
||||||
|
|
||||||
function assertPathExists(input: { label: string; filePath: string }): string {
|
function assertPathExists(input: { label: string; filePath: string }): string {
|
||||||
if (!existsSync(input.filePath)) {
|
if (!existsSync(input.filePath)) {
|
||||||
throw new Error(`${input.label} is missing at ${input.filePath}`);
|
throw new Error(`${input.label} is missing at ${input.filePath}`);
|
||||||
@@ -82,16 +88,11 @@ function assertPathExists(input: { label: string; filePath: string }): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function parseCliPassthroughArgsFromArgv(argv: string[]): string[] | null {
|
export function parseCliPassthroughArgsFromArgv(argv: string[]): string[] | null {
|
||||||
const startIndex = process.defaultApp ? 2 : 1;
|
return parseCliPassthroughArgs({
|
||||||
const effective = argv
|
argv,
|
||||||
.slice(startIndex)
|
isDefaultApp: process.defaultApp,
|
||||||
.filter(
|
forceCli: process.env[DESKTOP_CLI_ENV] === "1",
|
||||||
(arg) =>
|
});
|
||||||
!arg.startsWith(IGNORED_GUI_LAUNCH_ARG_PREFIX) &&
|
|
||||||
!arg.startsWith("--"),
|
|
||||||
);
|
|
||||||
|
|
||||||
return effective.length > 0 ? effective : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveDaemonRunnerEntrypoint(): NodeEntrypointSpec {
|
export function resolveDaemonRunnerEntrypoint(): NodeEntrypointSpec {
|
||||||
@@ -167,18 +168,39 @@ export function resolveCliEntrypoint(): NodeEntrypointSpec {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createElectronNodeEnv(baseEnv: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
|
export function createNodeEntrypointInvocation(input: {
|
||||||
return {
|
entrypoint: NodeEntrypointSpec;
|
||||||
...baseEnv,
|
argvMode: NodeEntrypointArgvMode;
|
||||||
ELECTRON_RUN_AS_NODE: "1",
|
args: string[];
|
||||||
};
|
baseEnv: NodeJS.ProcessEnv;
|
||||||
|
}): NodeEntrypointInvocation {
|
||||||
|
return createSharedNodeEntrypointInvocation({
|
||||||
|
execPath: process.execPath,
|
||||||
|
isPackaged: app.isPackaged,
|
||||||
|
packagedRunnerPath: app.isPackaged
|
||||||
|
? assertPathExists({
|
||||||
|
label: "Bundled node entrypoint runner",
|
||||||
|
filePath: resolvePackagedNodeEntrypointRunnerPath(),
|
||||||
|
})
|
||||||
|
: null,
|
||||||
|
entrypoint: input.entrypoint,
|
||||||
|
argvMode: input.argvMode,
|
||||||
|
args: input.args,
|
||||||
|
baseEnv: input.baseEnv,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function spawnCliProcess(args: string[]): SpawnSyncReturns<Buffer> {
|
function spawnCliProcess(args: string[]): SpawnSyncReturns<Buffer> {
|
||||||
const cli = resolveCliEntrypoint();
|
const cli = resolveCliEntrypoint();
|
||||||
|
const invocation = createNodeEntrypointInvocation({
|
||||||
|
entrypoint: cli,
|
||||||
|
argvMode: "bare",
|
||||||
|
args,
|
||||||
|
baseEnv: process.env,
|
||||||
|
});
|
||||||
|
|
||||||
return spawnSync(process.execPath, [...cli.execArgv, cli.entryPath, ...args], {
|
return spawnSync(invocation.command, invocation.args, {
|
||||||
env: createElectronNodeEnv(process.env),
|
env: invocation.env,
|
||||||
stdio: "inherit",
|
stdio: "inherit",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,9 @@
|
|||||||
"main": "build/index.js",
|
"main": "build/index.js",
|
||||||
"types": "build/index.d.ts",
|
"types": "build/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "expo-module build",
|
"build": "EXPO_NONINTERACTIVE=1 expo-module build",
|
||||||
"clean": "expo-module clean",
|
"clean": "expo-module clean",
|
||||||
|
"dev": "expo-module build",
|
||||||
"lint": "expo-module lint",
|
"lint": "expo-module lint",
|
||||||
"test": "expo-module test",
|
"test": "expo-module test",
|
||||||
"format": "biome check .",
|
"format": "biome check .",
|
||||||
|
|||||||
Reference in New Issue
Block a user