-
Notifications
You must be signed in to change notification settings - Fork 57
Expand file tree
/
Copy pathnode-shim.ts
More file actions
71 lines (63 loc) · 1.99 KB
/
Copy pathnode-shim.ts
File metadata and controls
71 lines (63 loc) · 1.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import {
chmodSync,
lstatSync,
mkdirSync,
readFileSync,
renameSync,
symlinkSync,
writeFileSync,
} from "node:fs";
import { join } from "node:path";
function isErrnoException(err: unknown): err is NodeJS.ErrnoException {
return err instanceof Error && "code" in err;
}
function escapeForDoubleQuotes(path: string): string {
return path.replace(/([$`"\\])/g, "\\$1");
}
export function buildNodeShimScript(execPath: string): string {
return [
"#!/bin/sh",
"export ELECTRON_RUN_AS_NODE=1",
`exec "${escapeForDoubleQuotes(execPath)}" "$@"`,
"",
].join("\n");
}
/**
* Writes the `node` shim agents resolve via PATH. On POSIX this is a wrapper
* script that sets ELECTRON_RUN_AS_NODE itself before exec'ing the app binary,
* so the shim stays a node runtime even when a layer in between (user dotfiles,
* direnv/flox, shell snapshots, MCP clients with cleaned envs) strips the var.
* A bare symlink relied on every descendant preserving the env and booted the
* full desktop app whenever one didn't. Replaces a stale legacy symlink or a
* wrapper pointing at a moved binary; no-op when already current.
*/
export function ensureNodeShim(
mockNodeDir: string,
execPath: string,
platform: NodeJS.Platform = process.platform,
): void {
mkdirSync(mockNodeDir, { recursive: true });
const shimPath = join(mockNodeDir, "node");
if (platform === "win32") {
try {
symlinkSync(execPath, shimPath);
} catch (err) {
if (!isErrnoException(err) || err.code !== "EEXIST") throw err;
}
return;
}
const script = buildNodeShimScript(execPath);
if (currentShimContent(shimPath) === script) return;
const tmpPath = `${shimPath}.${process.pid}.tmp`;
writeFileSync(tmpPath, script);
chmodSync(tmpPath, 0o755);
renameSync(tmpPath, shimPath);
}
function currentShimContent(shimPath: string): string | null {
try {
if (lstatSync(shimPath).isSymbolicLink()) return null;
return readFileSync(shimPath, "utf-8");
} catch {
return null;
}
}