History

[codex] Enforce canonical Node namespace imports (#3238)

Julius Marminge committed 4 months ago

Commit 2fa37ec1 parent db2750271 files · +1205 −952Browse files

Showing the changes to apps/desktop/scripts (7 of 71 files). Show all

Unified · Split

7 files
  1. apps/desktop/scripts/build-preview-annotation-css.mjs +16 −16
  2. apps/desktop/scripts/dev-electron.mjs +13 −9
  3. apps/desktop/scripts/electron-launcher.mjs +89 −73
  4. apps/desktop/scripts/ensure-electron-runtime.mjs +34 −32
  5. apps/desktop/scripts/smoke-test.mjs +7 −7
  6. apps/desktop/scripts/start-electron.mjs +2 −2
  7. apps/desktop/scripts/wait-for-resources.mjs +8 −8
apps/desktop/scripts/build-preview-annotation-css.mjs+16−16
@@ -1,23 +1,23 @@
1import { readFile, writeFile } from "node:fs/promises";1import * as NodeFSP from "node:fs/promises";
2import { createRequire } from "node:module";2import * as NodeModule from "node:module";
3import { dirname, join } from "node:path";3import * as NodePath from "node:path";
4import { fileURLToPath } from "node:url";4import * as NodeURL from "node:url";
5 5
6import { compile } from "tailwindcss";6import { compile } from "tailwindcss";
7 7
8const directory = dirname(fileURLToPath(import.meta.url));8const directory = NodePath.dirname(NodeURL.fileURLToPath(import.meta.url));
9const appRoot = join(directory, "..");9const appRoot = NodePath.join(directory, "..");
10const sourcePath = join(appRoot, "src", "preview", "Annotation.css");10const sourcePath = NodePath.join(appRoot, "src", "preview", "Annotation.css");
11const preloadPath = join(appRoot, "src", "preview", "PickPreload.ts");11const preloadPath = NodePath.join(appRoot, "src", "preview", "PickPreload.ts");
12const outputPath = join(appRoot, "src", "preview", "AnnotationStyles.generated.ts");12const outputPath = NodePath.join(appRoot, "src", "preview", "AnnotationStyles.generated.ts");
13const require = createRequire(import.meta.url);13const require = NodeModule.createRequire(import.meta.url);
14const tailwindRoot = dirname(require.resolve("tailwindcss/package.json"));14const tailwindRoot = NodePath.dirname(require.resolve("tailwindcss/package.json"));
15 15
16const [annotationSource, preloadSource, themeSource, preflightSource] = await Promise.all([16const [annotationSource, preloadSource, themeSource, preflightSource] = await Promise.all([
17 readFile(sourcePath, "utf8"),17 NodeFSP.readFile(sourcePath, "utf8"),
18 readFile(preloadPath, "utf8"),18 NodeFSP.readFile(preloadPath, "utf8"),
19 readFile(join(tailwindRoot, "theme.css"), "utf8"),19 NodeFSP.readFile(NodePath.join(tailwindRoot, "theme.css"), "utf8"),
20 readFile(join(tailwindRoot, "preflight.css"), "utf8"),20 NodeFSP.readFile(NodePath.join(tailwindRoot, "preflight.css"), "utf8"),
21]);21]);
22 22
23const candidates = new Set(23const candidates = new Set(
@@ -37,4 +37,4 @@ const encodedCss = `'${css · 13 unmodified lines
37 .replaceAll("\n", "\\n")}'`;37 .replaceAll("\n", "\\n")}'`;
38const moduleSource = `// Generated by scripts/build-preview-annotation-css.mjs. Do not edit.\nexport const previewAnnotationStyles =\n ${encodedCss};\n`;38const moduleSource = `// Generated by scripts/build-preview-annotation-css.mjs. Do not edit.\nexport const previewAnnotationStyles =\n ${encodedCss};\n`;
39 39
40await writeFile(outputPath, moduleSource);40await NodeFSP.writeFile(outputPath, moduleSource);
apps/desktop/scripts/dev-electron.mjs+13−9
@@ -1,7 +1,7 @@
1import { spawn, spawnSync } from "node:child_process";1import * as NodeChildProcess from "node:child_process";
2import { watch } from "node:fs";2import * as NodeFS from "node:fs";
3import * as NodeOS from "node:os";3import * as NodeOS from "node:os";
4import { join } from "node:path";4import * as NodePath from "node:path";
5 5
6import {6import {
7 desktopDir,7 desktopDir,
@@ -64,7 +64,7 @@ function killChildTreeByPid(pid, signal) { · 56 unmodified lines
64 return;64 return;
65 }65 }
66 66
67 spawnSync("pkill", [`-${signal}`, "-P", String(pid)], { stdio: "ignore" });67 NodeChildProcess.spawnSync("pkill", [`-${signal}`, "-P", String(pid)], { stdio: "ignore" });
68}68}
69 69
70function cleanupStaleDevApps() {70function cleanupStaleDevApps() {
@@ -72,7 +72,9 @@ function cleanupStaleDevApps() { · 1 unmodified line
72 return;72 return;
73 }73 }
74 74
75 spawnSync("pkill", ["-f", "--", `--t3code-dev-root=${desktopDir}`], { stdio: "ignore" });75 NodeChildProcess.spawnSync("pkill", ["-f", "--", `--t3code-dev-root=${desktopDir}`], {
76 stdio: "ignore",
77 });
76}78}
77 79
78function startApp() {80function startApp() {
@@ -87,7 +89,7 @@ function startApp() { · 8 unmodified lines
87 ? electronArgs89 ? electronArgs
88 : [...electronArgs, `--t3code-dev-root=${desktopDir}`, "dist-electron/main.cjs"];90 : [...electronArgs, `--t3code-dev-root=${desktopDir}`, "dist-electron/main.cjs"];
89 const electronCommand = resolveElectronLaunchCommand(launchArgs);91 const electronCommand = resolveElectronLaunchCommand(launchArgs);
90 const app = spawn(electronCommand.electronPath, electronCommand.args, {92 const app = NodeChildProcess.spawn(electronCommand.electronPath, electronCommand.args, {
91 cwd: desktopDir,93 cwd: desktopDir,
92 env: childEnv,94 env: childEnv,
93 stdio: "inherit",95 stdio: "inherit",
@@ -180,8 +182,8 @@ function scheduleRestart() { · 86 unmodified lines
180 182
181function startWatchers() {183function startWatchers() {
182 for (const { directory, files } of watchedDirectories) {184 for (const { directory, files } of watchedDirectories) {
183 const watcher = watch(185 const watcher = NodeFS.watch(
184 join(desktopDir, directory),186 NodePath.join(desktopDir, directory),
185 { persistent: true },187 { persistent: true },
186 (_eventType, filename) => {188 (_eventType, filename) => {
187 if (typeof filename !== "string" || !files.has(filename)) {189 if (typeof filename !== "string" || !files.has(filename)) {
@@ -202,7 +204,9 @@ function killChildTree(signal) { · 14 unmodified lines
202 }204 }
203 205
204 // Kill direct children as a final fallback in case normal shutdown leaves stragglers.206 // Kill direct children as a final fallback in case normal shutdown leaves stragglers.
205 spawnSync("pkill", [`-${signal}`, "-P", String(process.pid)], { stdio: "ignore" });207 NodeChildProcess.spawnSync("pkill", [`-${signal}`, "-P", String(process.pid)], {
208 stdio: "ignore",
209 });
206}210}
207 211
208async function shutdown(exitCode) {212async function shutdown(exitCode) {
apps/desktop/scripts/electron-launcher.mjs+89−73
@@ -1,29 +1,18 @@
1// This file mostly exists because we want dev mode to say "T3 Code (Dev)" instead of "electron"1// This file mostly exists because we want dev mode to say "T3 Code (Dev)" instead of "electron"
2 2
3import { spawnSync } from "node:child_process";3import * as NodeChildProcess from "node:child_process";
4import {4import * as NodeFS from "node:fs";
5 copyFileSync,5import * as NodeModule from "node:module";
6 chmodSync,
7 cpSync,
8 existsSync,
9 mkdirSync,
10 mkdtempSync,
11 readFileSync,
12 rmSync,
13 statSync,
14 writeFileSync,
15} from "node:fs";
16import { createRequire } from "node:module";
17import * as NodeOS from "node:os";6import * as NodeOS from "node:os";
18import { basename, dirname, join, resolve } from "node:path";7import * as NodePath from "node:path";
19import { fileURLToPath } from "node:url";8import * as NodeURL from "node:url";
20import { ensureElectronRuntime } from "./ensure-electron-runtime.mjs";9import { ensureElectronRuntime } from "./ensure-electron-runtime.mjs";
21 10
22const isDevelopment = Boolean(process.env.VITE_DEV_SERVER_URL);11const isDevelopment = Boolean(process.env.VITE_DEV_SERVER_URL);
23const __dirname = dirname(fileURLToPath(import.meta.url));12const __dirname = NodePath.dirname(NodeURL.fileURLToPath(import.meta.url));
24export const desktopDir = resolve(__dirname, "..");13export const desktopDir = NodePath.resolve(__dirname, "..");
25const repoRoot = resolve(desktopDir, "..", "..");14const repoRoot = NodePath.resolve(desktopDir, "..", "..");
26const devBundleIdSuffix = basename(repoRoot)15const devBundleIdSuffix = NodePath.basename(repoRoot)
27 .toLowerCase()16 .toLowerCase()
28 .replaceAll(/[^a-z0-9]+/g, "");17 .replaceAll(/[^a-z0-9]+/g, "");
29export const APP_DISPLAY_NAME = isDevelopment ? "T3 Code (Dev)" : "T3 Code (Alpha)";18export const APP_DISPLAY_NAME = isDevelopment ? "T3 Code (Dev)" : "T3 Code (Alpha)";
@@ -32,22 +21,35 @@ export const APP_BUNDLE_ID = isDevelopment · 2 unmodified lines
32 : "com.t3tools.t3code";21 : "com.t3tools.t3code";
33const APP_PROTOCOL_SCHEMES = isDevelopment ? ["t3code-dev"] : ["t3code"];22const APP_PROTOCOL_SCHEMES = isDevelopment ? ["t3code-dev"] : ["t3code"];
34const LAUNCHER_VERSION = 12;23const LAUNCHER_VERSION = 12;
35const defaultIconPath = join(desktopDir, "resources", "icon.icns");24const defaultIconPath = NodePath.join(desktopDir, "resources", "icon.icns");
36const developmentMacIconPngPath = join(repoRoot, "assets", "dev", "blueprint-macos-1024.png");25const developmentMacIconPngPath = NodePath.join(
26 repoRoot,
27 "assets",
28 "dev",
29 "blueprint-macos-1024.png",
30);
37// oxlint-disable-next-line t3code/no-global-process-runtime -- Standalone launcher script has no Effect runtime.31// oxlint-disable-next-line t3code/no-global-process-runtime -- Standalone launcher script has no Effect runtime.
38const hostPlatform = NodeOS.platform();32const hostPlatform = NodeOS.platform();
39 33
40function setPlistString(plistPath, key, value) {34function setPlistString(plistPath, key, value) {
41 const replaceResult = spawnSync("plutil", ["-replace", key, "-string", value, plistPath], {35 const replaceResult = NodeChildProcess.spawnSync(
42 encoding: "utf8",36 "plutil",
43 });37 ["-replace", key, "-string", value, plistPath],
38 {
39 encoding: "utf8",
40 },
41 );
44 if (replaceResult.status === 0) {42 if (replaceResult.status === 0) {
45 return;43 return;
46 }44 }
47 45
48 const insertResult = spawnSync("plutil", ["-insert", key, "-string", value, plistPath], {46 const insertResult = NodeChildProcess.spawnSync(
49 encoding: "utf8",47 "plutil",
50 });48 ["-insert", key, "-string", value, plistPath],
49 {
50 encoding: "utf8",
51 },
52 );
51 if (insertResult.status === 0) {53 if (insertResult.status === 0) {
52 return;54 return;
53 }55 }
@@ -58,16 +60,24 @@ function setPlistString(plistPath, key, value) { · 4 unmodified lines
58 60
59function setPlistJson(plistPath, key, value) {61function setPlistJson(plistPath, key, value) {
60 const serialized = JSON.stringify(value);62 const serialized = JSON.stringify(value);
61 const replaceResult = spawnSync("plutil", ["-replace", key, "-json", serialized, plistPath], {63 const replaceResult = NodeChildProcess.spawnSync(
62 encoding: "utf8",64 "plutil",
63 });65 ["-replace", key, "-json", serialized, plistPath],
66 {
67 encoding: "utf8",
68 },
69 );
64 if (replaceResult.status === 0) {70 if (replaceResult.status === 0) {
65 return;71 return;
66 }72 }
67 73
68 const insertResult = spawnSync("plutil", ["-insert", key, "-json", serialized, plistPath], {74 const insertResult = NodeChildProcess.spawnSync(
69 encoding: "utf8",75 "plutil",
70 });76 ["-insert", key, "-json", serialized, plistPath],
77 {
78 encoding: "utf8",
79 },
80 );
71 if (insertResult.status === 0) {81 if (insertResult.status === 0) {
72 return;82 return;
73 }83 }
@@ -77,7 +87,7 @@ function setPlistJson(plistPath, key, value) { · 3 unmodified lines
77}87}
78 88
79function runChecked(command, args) {89function runChecked(command, args) {
80 const result = spawnSync(command, args, { encoding: "utf8" });90 const result = NodeChildProcess.spawnSync(command, args, { encoding: "utf8" });
81 if (result.status === 0) {91 if (result.status === 0) {
82 return;92 return;
83 }93 }
@@ -91,7 +101,7 @@ function shellSingleQuote(value) { · 7 unmodified lines
91}101}
92 102
93function writeDevelopmentLauncherScript(targetBinaryPath, electronBinaryPath) {103function writeDevelopmentLauncherScript(targetBinaryPath, electronBinaryPath) {
94 const mainEntryPath = join(desktopDir, "dist-electron", "main.cjs");104 const mainEntryPath = NodePath.join(desktopDir, "dist-electron", "main.cjs");
95 const envEntries = [105 const envEntries = [
96 ["VITE_DEV_SERVER_URL", process.env.VITE_DEV_SERVER_URL],106 ["VITE_DEV_SERVER_URL", process.env.VITE_DEV_SERVER_URL],
97 ["T3CODE_PORT", process.env.T3CODE_PORT],107 ["T3CODE_PORT", process.env.T3CODE_PORT],
@@ -101,7 +111,7 @@ function writeDevelopmentLauncherScript(targetBinaryPath, electronBinaryPath) { · 3 unmodified lines
101 ["T3CODE_OTLP_EXPORT_INTERVAL_MS", process.env.T3CODE_OTLP_EXPORT_INTERVAL_MS],111 ["T3CODE_OTLP_EXPORT_INTERVAL_MS", process.env.T3CODE_OTLP_EXPORT_INTERVAL_MS],
102 ["T3CODE_DESKTOP_APP_USER_MODEL_ID", APP_BUNDLE_ID],112 ["T3CODE_DESKTOP_APP_USER_MODEL_ID", APP_BUNDLE_ID],
103 ].filter((entry) => typeof entry[1] === "string" && entry[1].trim().length > 0);113 ].filter((entry) => typeof entry[1] === "string" && entry[1].trim().length > 0);
104 writeFileSync(114 NodeFS.writeFileSync(
105 targetBinaryPath,115 targetBinaryPath,
106 [116 [
107 "#!/bin/sh",117 "#!/bin/sh",
@@ -110,7 +120,7 @@ function writeDevelopmentLauncherScript(targetBinaryPath, electronBinaryPath) { · 2 unmodified lines
110 "",120 "",
111 ].join("\n"),121 ].join("\n"),
112 );122 );
113 chmodSync(targetBinaryPath, 0o755);123 NodeFS.chmodSync(targetBinaryPath, 0o755);
114}124}
115 125
116function registerMacLauncherBundle(appBundlePath) {126function registerMacLauncherBundle(appBundlePath) {
@@ -140,21 +150,24 @@ function registerMacLauncherBundle(appBundlePath) { · 23 unmodified lines
140}150}
141 151
142function ensureDevelopmentIconIcns(runtimeDir) {152function ensureDevelopmentIconIcns(runtimeDir) {
143 const generatedIconPath = join(runtimeDir, "icon-dev.icns");153 const generatedIconPath = NodePath.join(runtimeDir, "icon-dev.icns");
144 mkdirSync(runtimeDir, { recursive: true });154 NodeFS.mkdirSync(runtimeDir, { recursive: true });
145 155
146 if (!existsSync(developmentMacIconPngPath)) {156 if (!NodeFS.existsSync(developmentMacIconPngPath)) {
147 return defaultIconPath;157 return defaultIconPath;
148 }158 }
149 159
150 const sourceMtimeMs = statSync(developmentMacIconPngPath).mtimeMs;160 const sourceMtimeMs = NodeFS.statSync(developmentMacIconPngPath).mtimeMs;
151 if (existsSync(generatedIconPath) && statSync(generatedIconPath).mtimeMs >= sourceMtimeMs) {161 if (
162 NodeFS.existsSync(generatedIconPath) &&
163 NodeFS.statSync(generatedIconPath).mtimeMs >= sourceMtimeMs
164 ) {
152 return generatedIconPath;165 return generatedIconPath;
153 }166 }
154 167
155 const iconsetRoot = mkdtempSync(join(runtimeDir, "dev-iconset-"));168 const iconsetRoot = NodeFS.mkdtempSync(NodePath.join(runtimeDir, "dev-iconset-"));
156 const iconsetDir = join(iconsetRoot, "icon.iconset");169 const iconsetDir = NodePath.join(iconsetRoot, "icon.iconset");
157 mkdirSync(iconsetDir, { recursive: true });170 NodeFS.mkdirSync(iconsetDir, { recursive: true });
158 171
159 try {172 try {
160 for (const size of [16, 32, 128, 256, 512]) {173 for (const size of [16, 32, 128, 256, 512]) {
@@ -164,7 +177,7 @@ function ensureDevelopmentIconIcns(runtimeDir) { · 3 unmodified lines
164 String(size),177 String(size),
165 developmentMacIconPngPath,178 developmentMacIconPngPath,
166 "--out",179 "--out",
167 join(iconsetDir, `icon_${size}x${size}.png`),180 NodePath.join(iconsetDir, `icon_${size}x${size}.png`),
168 ]);181 ]);
169 182
170 const retinaSize = size * 2;183 const retinaSize = size * 2;
@@ -174,7 +187,7 @@ function ensureDevelopmentIconIcns(runtimeDir) { · 3 unmodified lines
174 String(retinaSize),187 String(retinaSize),
175 developmentMacIconPngPath,188 developmentMacIconPngPath,
176 "--out",189 "--out",
177 join(iconsetDir, `icon_${size}x${size}@2x.png`),190 NodePath.join(iconsetDir, `icon_${size}x${size}@2x.png`),
178 ]);191 ]);
179 }192 }
180 193
@@ -187,12 +200,12 @@ function ensureDevelopmentIconIcns(runtimeDir) { · 6 unmodified lines
187 );200 );
188 return defaultIconPath;201 return defaultIconPath;
189 } finally {202 } finally {
190 rmSync(iconsetRoot, { recursive: true, force: true });203 NodeFS.rmSync(iconsetRoot, { recursive: true, force: true });
191 }204 }
192}205}
193 206
194function patchMainBundleInfoPlist(appBundlePath, iconPath) {207function patchMainBundleInfoPlist(appBundlePath, iconPath) {
195 const infoPlistPath = join(appBundlePath, "Contents", "Info.plist");208 const infoPlistPath = NodePath.join(appBundlePath, "Contents", "Info.plist");
196 setPlistString(infoPlistPath, "CFBundleDisplayName", APP_DISPLAY_NAME);209 setPlistString(infoPlistPath, "CFBundleDisplayName", APP_DISPLAY_NAME);
197 setPlistString(infoPlistPath, "CFBundleName", APP_DISPLAY_NAME);210 setPlistString(infoPlistPath, "CFBundleName", APP_DISPLAY_NAME);
198 setPlistString(infoPlistPath, "CFBundleIdentifier", APP_BUNDLE_ID);211 setPlistString(infoPlistPath, "CFBundleIdentifier", APP_BUNDLE_ID);
@@ -204,9 +217,9 @@ function patchMainBundleInfoPlist(appBundlePath, iconPath) { · 5 unmodified lines
204 },217 },
205 ]);218 ]);
206 219
207 const resourcesDir = join(appBundlePath, "Contents", "Resources");220 const resourcesDir = NodePath.join(appBundlePath, "Contents", "Resources");
208 copyFileSync(iconPath, join(resourcesDir, "icon.icns"));221 NodeFS.copyFileSync(iconPath, NodePath.join(resourcesDir, "icon.icns"));
209 copyFileSync(iconPath, join(resourcesDir, "electron.icns"));222 NodeFS.copyFileSync(iconPath, NodePath.join(resourcesDir, "electron.icns"));
210}223}
211 224
212function patchHelperBundleInfoPlists(appBundlePath) {225function patchHelperBundleInfoPlists(appBundlePath) {
@@ -218,7 +231,7 @@ function patchHelperBundleInfoPlists(appBundlePath) { · 5 unmodified lines
218 ];231 ];
219 232
220 for (const [bundleName, bundleIdentifierSuffix, bundleDisplayName] of helperBundleNames) {233 for (const [bundleName, bundleIdentifierSuffix, bundleDisplayName] of helperBundleNames) {
221 const infoPlistPath = join(234 const infoPlistPath = NodePath.join(
222 appBundlePath,235 appBundlePath,
223 "Contents",236 "Contents",
224 "Frameworks",237 "Frameworks",
@@ -226,7 +239,7 @@ function patchHelperBundleInfoPlists(appBundlePath) { · 1 unmodified line
226 "Contents",239 "Contents",
227 "Info.plist",240 "Info.plist",
228 );241 );
229 if (!existsSync(infoPlistPath)) {242 if (!NodeFS.existsSync(infoPlistPath)) {
230 continue;243 continue;
231 }244 }
232 245
@@ -242,34 +255,34 @@ function patchHelperBundleInfoPlists(appBundlePath) { · 9 unmodified lines
242 255
243function readJson(path) {256function readJson(path) {
244 try {257 try {
245 return JSON.parse(readFileSync(path, "utf8"));258 return JSON.parse(NodeFS.readFileSync(path, "utf8"));
246 } catch {259 } catch {
247 return null;260 return null;
248 }261 }
249}262}
250 263
251function buildMacLauncher(electronBinaryPath) {264function buildMacLauncher(electronBinaryPath) {
252 const sourceAppBundlePath = resolve(dirname(electronBinaryPath), "../..");265 const sourceAppBundlePath = NodePath.resolve(NodePath.dirname(electronBinaryPath), "../..");
253 const runtimeDir = join(desktopDir, ".electron-runtime");266 const runtimeDir = NodePath.join(desktopDir, ".electron-runtime");
254 const targetAppBundlePath = join(runtimeDir, `${APP_DISPLAY_NAME}.app`);267 const targetAppBundlePath = NodePath.join(runtimeDir, `${APP_DISPLAY_NAME}.app`);
255 const targetBinaryPath = join(targetAppBundlePath, "Contents", "MacOS", "Electron");268 const targetBinaryPath = NodePath.join(targetAppBundlePath, "Contents", "MacOS", "Electron");
256 const iconPath = isDevelopment ? ensureDevelopmentIconIcns(runtimeDir) : defaultIconPath;269 const iconPath = isDevelopment ? ensureDevelopmentIconIcns(runtimeDir) : defaultIconPath;
257 const metadataPath = join(runtimeDir, "metadata.json");270 const metadataPath = NodePath.join(runtimeDir, "metadata.json");
258 271
259 mkdirSync(runtimeDir, { recursive: true });272 NodeFS.mkdirSync(runtimeDir, { recursive: true });
260 273
261 const expectedMetadata = {274 const expectedMetadata = {
262 launcherVersion: LAUNCHER_VERSION,275 launcherVersion: LAUNCHER_VERSION,
263 sourceAppBundlePath,276 sourceAppBundlePath,
264 sourceAppMtimeMs: statSync(sourceAppBundlePath).mtimeMs,277 sourceAppMtimeMs: NodeFS.statSync(sourceAppBundlePath).mtimeMs,
265 iconMtimeMs: statSync(iconPath).mtimeMs,278 iconMtimeMs: NodeFS.statSync(iconPath).mtimeMs,
266 appBundleId: APP_BUNDLE_ID,279 appBundleId: APP_BUNDLE_ID,
267 appProtocolSchemes: APP_PROTOCOL_SCHEMES,280 appProtocolSchemes: APP_PROTOCOL_SCHEMES,
268 };281 };
269 282
270 const currentMetadata = readJson(metadataPath);283 const currentMetadata = readJson(metadataPath);
271 if (284 if (
272 existsSync(targetBinaryPath) &&285 NodeFS.existsSync(targetBinaryPath) &&
273 currentMetadata &&286 currentMetadata &&
274 JSON.stringify(currentMetadata) === JSON.stringify(expectedMetadata)287 JSON.stringify(currentMetadata) === JSON.stringify(expectedMetadata)
275 ) {288 ) {
@@ -277,18 +290,21 @@ function buildMacLauncher(electronBinaryPath) { · 1 unmodified line
277 return targetBinaryPath;290 return targetBinaryPath;
278 }291 }
279 292
280 rmSync(targetAppBundlePath, { recursive: true, force: true });293 NodeFS.rmSync(targetAppBundlePath, { recursive: true, force: true });
281 // verbatimSymlinks keeps the framework's relative symlinks intact294 // verbatimSymlinks keeps the framework's relative symlinks intact
282 // (e.g. Resources -> Versions/Current/Resources). Without it cpSync295 // (e.g. Resources -> Versions/Current/Resources). Without it cpSync
283 // rewrites them to absolute paths into node_modules, which escape the296 // rewrites them to absolute paths into node_modules, which escape the
284 // bundle and crash sandboxed helper processes (icudtl.dat not found).297 // bundle and crash sandboxed helper processes (icudtl.dat not found).
285 cpSync(sourceAppBundlePath, targetAppBundlePath, { recursive: true, verbatimSymlinks: true });298 NodeFS.cpSync(sourceAppBundlePath, targetAppBundlePath, {
299 recursive: true,
300 verbatimSymlinks: true,
301 });
286 patchMainBundleInfoPlist(targetAppBundlePath, iconPath);302 patchMainBundleInfoPlist(targetAppBundlePath, iconPath);
287 patchHelperBundleInfoPlists(targetAppBundlePath);303 patchHelperBundleInfoPlists(targetAppBundlePath);
288 if (isDevelopment) {304 if (isDevelopment) {
289 writeDevelopmentLauncherScript(targetBinaryPath, electronBinaryPath);305 writeDevelopmentLauncherScript(targetBinaryPath, electronBinaryPath);
290 }306 }
291 writeFileSync(metadataPath, `${JSON.stringify(expectedMetadata, null, 2)}\n`);307 NodeFS.writeFileSync(metadataPath, `${JSON.stringify(expectedMetadata, null, 2)}\n`);
292 registerMacLauncherBundle(targetAppBundlePath);308 registerMacLauncherBundle(targetAppBundlePath);
293 309
294 return targetBinaryPath;310 return targetBinaryPath;
@@ -299,9 +315,9 @@ function isLinuxSetuidSandboxConfigured(electronBinaryPath) { · 4 unmodified lines
299 return true;315 return true;
300 }316 }
301 317
302 const sandboxPath = join(dirname(electronBinaryPath), "chrome-sandbox");318 const sandboxPath = NodePath.join(NodePath.dirname(electronBinaryPath), "chrome-sandbox");
303 try {319 try {
304 const sandboxStat = statSync(sandboxPath);320 const sandboxStat = NodeFS.statSync(sandboxPath);
305 return sandboxStat.uid === 0 && (sandboxStat.mode & 0o4777) === 0o4755;321 return sandboxStat.uid === 0 && (sandboxStat.mode & 0o4777) === 0o4755;
306 } catch {322 } catch {
307 return false;323 return false;
@@ -322,7 +338,7 @@ function resolveLinuxSandboxArgs(electronBinaryPath) { · 14 unmodified lines
322export function resolveElectronPath() {338export function resolveElectronPath() {
323 ensureElectronRuntime();339 ensureElectronRuntime();
324 340
325 const require = createRequire(import.meta.url);341 const require = NodeModule.createRequire(import.meta.url);
326 const electronBinaryPath = require("electron");342 const electronBinaryPath = require("electron");
327 343
328 if (hostPlatform !== "darwin") {344 if (hostPlatform !== "darwin") {
@@ -345,11 +361,11 @@ export function resolveDevProtocolClient() { · 16 unmodified lines
345 return null;361 return null;
346 }362 }
347 363
348 const require = createRequire(import.meta.url);364 const require = NodeModule.createRequire(import.meta.url);
349 const electronBinaryPath = require("electron");365 const electronBinaryPath = require("electron");
350 const launcherBinaryPath = buildMacLauncher(electronBinaryPath);366 const launcherBinaryPath = buildMacLauncher(electronBinaryPath);
351 return {367 return {
352 appBundlePath: resolve(launcherBinaryPath, "..", "..", ".."),368 appBundlePath: NodePath.resolve(launcherBinaryPath, "..", "..", ".."),
353 appBundleId: APP_BUNDLE_ID,369 appBundleId: APP_BUNDLE_ID,
354 };370 };
355}371}
apps/desktop/scripts/ensure-electron-runtime.mjs+34−32
@@ -1,14 +1,14 @@
1import { chmodSync, existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";1import * as NodeFS from "node:fs";
2import { createRequire } from "node:module";2import * as NodeModule from "node:module";
3import { arch, platform, tmpdir } from "node:os";3import * as NodeOS from "node:os";
4import { dirname, join } from "node:path";4import * as NodePath from "node:path";
5import { spawnSync } from "node:child_process";5import * as NodeChildProcess from "node:child_process";
6 6
7const require = createRequire(import.meta.url);7const require = NodeModule.createRequire(import.meta.url);
8// oxlint-disable-next-line t3code/no-global-process-runtime -- Standalone repair script has no Effect runtime.8// oxlint-disable-next-line t3code/no-global-process-runtime -- Standalone repair script has no Effect runtime.
9const hostPlatform = platform();9const hostPlatform = NodeOS.platform();
10// oxlint-disable-next-line t3code/no-global-process-runtime -- Standalone repair script has no Effect runtime.10// oxlint-disable-next-line t3code/no-global-process-runtime -- Standalone repair script has no Effect runtime.
11const hostArch = arch();11const hostArch = NodeOS.arch();
12 12
13function getPlatformPath() {13function getPlatformPath() {
14 switch (hostPlatform) {14 switch (hostPlatform) {
@@ -27,26 +27,28 @@ function getPlatformPath() { · 12 unmodified lines
27 27
28function ensureExecutable(filePath) {28function ensureExecutable(filePath) {
29 if (hostPlatform !== "win32") {29 if (hostPlatform !== "win32") {
30 chmodSync(filePath, 0o755);30 NodeFS.chmodSync(filePath, 0o755);
31 }31 }
32}32}
33 33
34function repairPathFile(electronDir, platformPath) {34function repairPathFile(electronDir, platformPath) {
35 const pathFile = join(electronDir, "path.txt");35 const pathFile = NodePath.join(electronDir, "path.txt");
36 const currentPath = existsSync(pathFile) ? readFileSync(pathFile, "utf8") : undefined;36 const currentPath = NodeFS.existsSync(pathFile)
37 ? NodeFS.readFileSync(pathFile, "utf8")
38 : undefined;
37 39
38 if (currentPath !== platformPath) {40 if (currentPath !== platformPath) {
39 writeFileSync(pathFile, platformPath);41 NodeFS.writeFileSync(pathFile, platformPath);
40 }42 }
41}43}
42 44
43function getRequiredRuntimePaths(electronDir, platformPath) {45function getRequiredRuntimePaths(electronDir, platformPath) {
44 const paths = [join(electronDir, "dist", platformPath)];46 const paths = [NodePath.join(electronDir, "dist", platformPath)];
45 47
46 if (hostPlatform === "darwin") {48 if (hostPlatform === "darwin") {
47 paths.push(49 paths.push(
48 join(electronDir, "dist", "Electron.app", "Contents", "Info.plist"),50 NodePath.join(electronDir, "dist", "Electron.app", "Contents", "Info.plist"),
49 join(51 NodePath.join(
50 electronDir,52 electronDir,
51 "dist",53 "dist",
52 "Electron.app",54 "Electron.app",
@@ -66,7 +68,7 @@ function isMachO(filePath) { · 13 unmodified lines
66 return true;68 return true;
67 }69 }
68 70
69 const result = spawnSync("file", ["-b", filePath], {71 const result = NodeChildProcess.spawnSync("file", ["-b", filePath], {
70 encoding: "utf8",72 encoding: "utf8",
71 });73 });
72 74
@@ -75,7 +77,7 @@ function isMachO(filePath) { · 2 unmodified lines
75 77
76function missingRuntimePaths(electronDir, platformPath) {78function missingRuntimePaths(electronDir, platformPath) {
77 return getRequiredRuntimePaths(electronDir, platformPath).filter((runtimePath) => {79 return getRequiredRuntimePaths(electronDir, platformPath).filter((runtimePath) => {
78 return !existsSync(runtimePath);80 return !NodeFS.existsSync(runtimePath);
79 });81 });
80}82}
81 83
@@ -85,8 +87,8 @@ function invalidRuntimePaths(electronDir, platformPath) { · 3 unmodified lines
85 }87 }
86 88
87 return [89 return [
88 join(electronDir, "dist", platformPath),90 NodePath.join(electronDir, "dist", platformPath),
89 join(91 NodePath.join(
90 electronDir,92 electronDir,
91 "dist",93 "dist",
92 "Electron.app",94 "Electron.app",
@@ -95,11 +97,11 @@ function invalidRuntimePaths(electronDir, platformPath) { · 2 unmodified lines
95 "Electron Framework.framework",97 "Electron Framework.framework",
96 "Electron Framework",98 "Electron Framework",
97 ),99 ),
98 ].filter((runtimePath) => existsSync(runtimePath) && !isMachO(runtimePath));100 ].filter((runtimePath) => NodeFS.existsSync(runtimePath) && !isMachO(runtimePath));
99}101}
100 102
101function runChecked(command, args) {103function runChecked(command, args) {
102 const result = spawnSync(command, args, {104 const result = NodeChildProcess.spawnSync(command, args, {
103 encoding: "utf8",105 encoding: "utf8",
104 stdio: "inherit",106 stdio: "inherit",
105 });107 });
@@ -114,8 +116,8 @@ function runChecked(command, args) { · 8 unmodified lines
114}116}
115 117
116function installElectronRuntime(electronDir, version) {118function installElectronRuntime(electronDir, version) {
117 const tempDir = mkdtempSync(join(tmpdir(), "t3-electron-"));119 const tempDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-electron-"));
118 const zipPath = join(tempDir, `electron-v${version}-${hostPlatform}-${hostArch}.zip`);120 const zipPath = NodePath.join(tempDir, `electron-v${version}-${hostPlatform}-${hostArch}.zip`);
119 121
120 try {122 try {
121 runChecked("curl", [123 runChecked("curl", [
@@ -125,34 +127,34 @@ function installElectronRuntime(electronDir, version) { · 3 unmodified lines
125 zipPath,127 zipPath,
126 ]);128 ]);
127 if (hostPlatform === "darwin") {129 if (hostPlatform === "darwin") {
128 runChecked("ditto", ["-x", "-k", zipPath, join(electronDir, "dist")]);130 runChecked("ditto", ["-x", "-k", zipPath, NodePath.join(electronDir, "dist")]);
129 } else {131 } else {
130 runChecked("python3", [132 runChecked("python3", [
131 "-c",133 "-c",
132 "import os, sys, zipfile; os.makedirs(sys.argv[2], exist_ok=True); zipfile.ZipFile(sys.argv[1]).extractall(sys.argv[2])",134 "import os, sys, zipfile; os.makedirs(sys.argv[2], exist_ok=True); zipfile.ZipFile(sys.argv[1]).extractall(sys.argv[2])",
133 zipPath,135 zipPath,
134 join(electronDir, "dist"),136 NodePath.join(electronDir, "dist"),
135 ]);137 ]);
136 }138 }
137 } finally {139 } finally {
138 rmSync(tempDir, { recursive: true, force: true });140 NodeFS.rmSync(tempDir, { recursive: true, force: true });
139 }141 }
140}142}
141 143
142export function ensureElectronRuntime() {144export function ensureElectronRuntime() {
143 const electronPackageJsonPath = require.resolve("electron/package.json");145 const electronPackageJsonPath = require.resolve("electron/package.json");
144 const electronPackageJson = JSON.parse(readFileSync(electronPackageJsonPath, "utf8"));146 const electronPackageJson = JSON.parse(NodeFS.readFileSync(electronPackageJsonPath, "utf8"));
145 const electronDir = dirname(electronPackageJsonPath);147 const electronDir = NodePath.dirname(electronPackageJsonPath);
146 const platformPath = getPlatformPath();148 const platformPath = getPlatformPath();
147 const electronPath = join(electronDir, "dist", platformPath);149 const electronPath = NodePath.join(electronDir, "dist", platformPath);
148 const missingBeforeInstall = missingRuntimePaths(electronDir, platformPath);150 const missingBeforeInstall = missingRuntimePaths(electronDir, platformPath);
149 const invalidBeforeInstall = invalidRuntimePaths(electronDir, platformPath);151 const invalidBeforeInstall = invalidRuntimePaths(electronDir, platformPath);
150 152
151 if (missingBeforeInstall.length > 0 || invalidBeforeInstall.length > 0) {153 if (missingBeforeInstall.length > 0 || invalidBeforeInstall.length > 0) {
152 if (existsSync(join(electronDir, "dist"))) {154 if (NodeFS.existsSync(NodePath.join(electronDir, "dist"))) {
153 rmSync(join(electronDir, "dist"), { recursive: true, force: true });155 NodeFS.rmSync(NodePath.join(electronDir, "dist"), { recursive: true, force: true });
154 }156 }
155 rmSync(join(electronDir, "path.txt"), { force: true });157 NodeFS.rmSync(NodePath.join(electronDir, "path.txt"), { force: true });
156 installElectronRuntime(electronDir, electronPackageJson.version);158 installElectronRuntime(electronDir, electronPackageJson.version);
157 }159 }
158 160
apps/desktop/scripts/smoke-test.mjs+7−7
@@ -1,16 +1,16 @@
1import { spawn } from "node:child_process";1import * as NodeChildProcess from "node:child_process";
2import { dirname, resolve } from "node:path";2import * as NodePath from "node:path";
3import { fileURLToPath } from "node:url";3import * as NodeURL from "node:url";
4import { resolveElectronLaunchCommand } from "./electron-launcher.mjs";4import { resolveElectronLaunchCommand } from "./electron-launcher.mjs";
5 5
6const __dirname = dirname(fileURLToPath(import.meta.url));6const __dirname = NodePath.dirname(NodeURL.fileURLToPath(import.meta.url));
7const desktopDir = resolve(__dirname, "..");7const desktopDir = NodePath.resolve(__dirname, "..");
8const mainJs = resolve(desktopDir, "dist-electron/main.cjs");8const mainJs = NodePath.resolve(desktopDir, "dist-electron/main.cjs");
9 9
10console.log("\nLaunching Electron smoke test...");10console.log("\nLaunching Electron smoke test...");
11 11
12const electronCommand = resolveElectronLaunchCommand([mainJs]);12const electronCommand = resolveElectronLaunchCommand([mainJs]);
13const child = spawn(electronCommand.electronPath, electronCommand.args, {13const child = NodeChildProcess.spawn(electronCommand.electronPath, electronCommand.args, {
14 stdio: ["pipe", "pipe", "pipe"],14 stdio: ["pipe", "pipe", "pipe"],
15 env: {15 env: {
16 ...process.env,16 ...process.env,
apps/desktop/scripts/start-electron.mjs+2−2
@@ -1,4 +1,4 @@
1import { spawn } from "node:child_process";1import * as NodeChildProcess from "node:child_process";
2 2
3import { desktopDir, resolveElectronLaunchCommand } from "./electron-launcher.mjs";3import { desktopDir, resolveElectronLaunchCommand } from "./electron-launcher.mjs";
4 4
@@ -6,7 +6,7 @@ const childEnv = { ...process.env }; · 1 unmodified line
6delete childEnv.ELECTRON_RUN_AS_NODE;6delete childEnv.ELECTRON_RUN_AS_NODE;
7 7
8const electronCommand = resolveElectronLaunchCommand(["dist-electron/main.cjs"]);8const electronCommand = resolveElectronLaunchCommand(["dist-electron/main.cjs"]);
9const child = spawn(electronCommand.electronPath, electronCommand.args, {9const child = NodeChildProcess.spawn(electronCommand.electronPath, electronCommand.args, {
10 stdio: "inherit",10 stdio: "inherit",
11 cwd: desktopDir,11 cwd: desktopDir,
12 env: childEnv,12 env: childEnv,
apps/desktop/scripts/wait-for-resources.mjs+8−8
@@ -1,13 +1,13 @@
1import * as FileSystem from "node:fs/promises";1import * as NodeFSP from "node:fs/promises";
2import * as Net from "node:net";2import * as NodeNet from "node:net";
3import * as Path from "node:path";3import * as NodePath from "node:path";
4import * as Timers from "node:timers/promises";4import * as NodeTimersPromises from "node:timers/promises";
5 5
6const defaultTcpHosts = ["127.0.0.1", "localhost", "::1"];6const defaultTcpHosts = ["127.0.0.1", "localhost", "::1"];
7 7
8async function fileExists(filePath) {8async function fileExists(filePath) {
9 try {9 try {
10 await FileSystem.access(filePath);10 await NodeFSP.access(filePath);
11 return true;11 return true;
12 } catch {12 } catch {
13 return false;13 return false;
@@ -16,7 +16,7 @@ async function fileExists(filePath) { · 2 unmodified lines
16 16
17function tcpPortIsReady({ host, port, connectTimeoutMs = 500 }) {17function tcpPortIsReady({ host, port, connectTimeoutMs = 500 }) {
18 return new Promise((resolveReady) => {18 return new Promise((resolveReady) => {
19 const socket = Net.createConnection({ host, port });19 const socket = NodeNet.createConnection({ host, port });
20 let settled = false;20 let settled = false;
21 21
22 const finish = (ready) => {22 const finish = (ready) => {
@@ -47,7 +47,7 @@ async function resolvePendingResources({ baseDir, files, tcpPort, tcpHosts, conn · 24 unmodified lines
47 const pendingFiles = [];47 const pendingFiles = [];
48 48
49 for (const relativeFilePath of files) {49 for (const relativeFilePath of files) {
50 const ready = await fileExists(Path.resolve(baseDir, relativeFilePath));50 const ready = await fileExists(NodePath.resolve(baseDir, relativeFilePath));
51 if (!ready) {51 if (!ready) {
52 pendingFiles.push(relativeFilePath);52 pendingFiles.push(relativeFilePath);
53 }53 }
@@ -114,6 +114,6 @@ export async function waitForResources({ · 60 unmodified lines
114 );114 );
115 }115 }
116 116
117 await Timers.setTimeout(intervalMs);117 await NodeTimersPromises.setTimeout(intervalMs);
118 }118 }
119}119}