positron.js 1.0.6 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/packager.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const fs = require("fs");
2
2
  const path = require("path");
3
- const { execSync, execFileSync } = require("child_process");
3
+ const { execSync, execFileSync, spawnSync } = require("child_process");
4
4
  const { info, error, success } = require("./logs");
5
5
  const https = require("https");
6
6
  const esbuild = require("esbuild");
@@ -8,7 +8,8 @@ const findPackageJson = require("./findpackage");
8
8
 
9
9
  const MAJOR_NODE_V = 24;
10
10
 
11
- const ob = process.argv.includes("--obfuscate");
11
+ const min = process.argv.includes("--minify") || process.argv.includes("--min");
12
+ const ob = process.argv.includes("--obfuscate") || process.argv.includes("--ob");
12
13
 
13
14
  const arch = process.argv.includes("--x64") ? "x64" : process.argv.includes("--arm64") ? "arm64" : process.arch;
14
15
 
@@ -22,13 +23,25 @@ function performPackager() {
22
23
  if (fs.existsSync(distDir)) fs.rmSync(distDir, { recursive: true, force: true });
23
24
  fs.mkdirSync(distDir, { recursive: true });
24
25
 
26
+ let selectedPlatform = false;
27
+
25
28
  if (process.argv.includes("--mac") || process.argv.includes("--m")) {
26
29
  packageMacOS(appRoot, distDir, appName);
27
- } else if (process.argv.includes("--windows") || process.argv.includes("--w")) {
30
+ selectedPlatform = true;
31
+ }
32
+ if (process.argv.includes("--windows") || process.argv.includes("--w")) {
28
33
  packageWindows(appRoot, distDir, appName);
29
- } else {
30
- process.platform === "win32" ? packageWindows(appRoot, distDir, appName) : packageMacOS(appRoot, distDir, appName);
31
- }
34
+ selectedPlatform = true;
35
+ }
36
+ if (process.argv.includes("--linux") || process.argv.includes("--l")) {
37
+ packageLinux(appRoot, distDir, appName);
38
+ selectedPlatform = true;
39
+ }
40
+
41
+ if (selectedPlatform) return;
42
+ if (process.platform === "win32") packageWindows(appRoot, distDir, appName);
43
+ else if (process.platform === "linux") packageLinux(appRoot, distDir, appName);
44
+ else packageMacOS(appRoot, distDir, appName);
32
45
  }
33
46
 
34
47
  function handleJavaScriptPipeline(appRoot, resourcesPath) {
@@ -89,7 +102,7 @@ async function packageMacOS(appRoot, distDir, appName) {
89
102
  <key>CFBundleExecutable</key>
90
103
  <string>${appName}</string>
91
104
  <key>CFBundleIdentifier</key>
92
- <string>com.${package.author || "positron"}.${appName.toLowerCase()}</string>
105
+ <string>${package.bundleIdentifier || `com.${package.author || "positron"}.${appName.toLowerCase()}`}</string>
93
106
  <key>CFBundleName</key>
94
107
  <string>${appName}</string>
95
108
  <key>CFBundlePackageType</key>
@@ -215,6 +228,57 @@ async function packageWindows(appRoot, distDir, appName) {
215
228
  success(`Successfully packaged Windows app directory at: ${outputFolder}`);
216
229
  }
217
230
 
231
+ async function packageLinux(appRoot, distDir, appName) {
232
+ const outputFolder = path.join(distDir, `${appName}-linux`);
233
+ fs.mkdirSync(outputFolder, { recursive: true });
234
+
235
+ info(`[Packager] Creating Linux App structure...`);
236
+
237
+ const binFolder = path.join(appRoot, "bin");
238
+ const compiledBinary = path.join(binFolder, "positron-runtime");
239
+
240
+ if (!fs.existsSync(compiledBinary)) {
241
+ error("Fatal: Native compiled binary missing from bin/. Run build first.");
242
+ process.exit(1);
243
+ }
244
+
245
+ const binaryPath = path.join(outputFolder, appName);
246
+ fs.copyFileSync(compiledBinary, binaryPath);
247
+ fs.chmodSync(binaryPath, "755");
248
+
249
+ const resourcesPath = path.join(outputFolder, "resources");
250
+ fs.mkdirSync(resourcesPath, { recursive: true });
251
+
252
+ handleJavaScriptPipeline(appRoot, resourcesPath);
253
+
254
+ const bundledJs = path.join(resourcesPath, "index.js");
255
+ const backendName = appName.replace(/([a-z0-9])([A-Z])/g, '$1-$2').replace(/[\s_]+/g, '-').toLowerCase() + '-backend';
256
+
257
+ if (fs.existsSync(bundledJs)) {
258
+ await compileWithPkg(bundledJs, "linux", resourcesPath, backendName);
259
+ } else {
260
+ error(`[Packager] Fatal: Bundled JavaScript entry point missing at ${bundledJs}`);
261
+ process.exit(1);
262
+ }
263
+
264
+ const desktopContent = `[Desktop Entry]
265
+ Name=${appName}
266
+ Exec=./${appName}
267
+ Icon=utilities-terminal
268
+ Type=Application
269
+ Categories=Utility;`;
270
+ fs.writeFileSync(path.join(outputFolder, `${appName}.desktop`), desktopContent);
271
+
272
+ if(!process.argv.includes('--keep-package-json') || !process.argv.includes('--kpj')) {
273
+ fs.rmSync(path.join(resourcesPath, "package.json"), { force: true });
274
+ }
275
+
276
+ fs.rmSync(path.join(resourcesPath, "icon.icns"), { force: true });
277
+ fs.rmSync(path.join(resourcesPath, "icon.ico"), { force: true });
278
+
279
+ success(`Successfully packaged Linux app directory at: ${outputFolder}`);
280
+ }
281
+
218
282
  function copyAppAssets(src, dest, ignoredFiles = []) {
219
283
  const ignoreList = ["node_modules", "dist", "bin", ".git"];
220
284
 
@@ -238,6 +302,34 @@ function copyAppAssets(src, dest, ignoredFiles = []) {
238
302
  copyRecursive(srcPath, destPath);
239
303
  } else {
240
304
  fs.copyFileSync(srcPath, destPath);
305
+
306
+ if(min && item.endsWith(".js")) {
307
+ info(`Minifying JavaScript file: ${destPath}`);
308
+ try {
309
+ esbuild.buildSync({
310
+ "bundle": false,
311
+ "minify": true,
312
+ "sourcemap": false,
313
+ "target": `node${MAJOR_NODE_V}`,
314
+ "entryPoints": [srcPath],
315
+ "outfile": destPath,
316
+ })
317
+ } catch (err) {
318
+ error(`JavaScript minification failed for ${destPath}:`, err);
319
+ }
320
+ }
321
+
322
+ if(ob && item.endsWith(".js")) {
323
+ info(`Obfuscating JavaScript file: ${destPath}`);
324
+ try {
325
+ const obResult = spawnSync("npx", ["javascript-obfuscator", destPath, "--compact", "true", "--self-defending", "true", "--string-array", "true", "--string-array-encoding", "base64", "--string-array-threshold", "1", "--output", destPath], { stdio:"inherit" });
326
+ if (obResult.error) throw obResult.error;
327
+ if (obResult.status !== 0) throw new Error("javascript-obfuscator failed");
328
+ } catch (err) {
329
+ error(`JavaScript obfuscation failed for ${destPath}:`, err);
330
+ }
331
+ }
332
+
241
333
  }
242
334
  }
243
335
  }
@@ -268,6 +360,8 @@ async function compileWithPkg(bundledJsPath, targetPlatform, outputFolder, appNa
268
360
  finalBinaryName = `${appName}.exe`;
269
361
  } else if (targetPlatform === "darwin") {
270
362
  pkgTarget = `node${MAJOR_NODE_V}-macos-${arch}`;
363
+ } else if (targetPlatform === "linux") {
364
+ pkgTarget = `node${MAJOR_NODE_V}-linux-${arch}`;
271
365
  }
272
366
 
273
367
  const outputPath = path.join(outputFolder, finalBinaryName);
package/screen.js CHANGED
@@ -1,4 +1,4 @@
1
- const { execSync } = require('child_process');
1
+ const { spawnSync } = require('child_process');
2
2
 
3
3
  /**
4
4
  * Gets the screen size of the primary display. The implementation varies based on the operating system:
@@ -11,16 +11,18 @@ function getScreenSize() {
11
11
 
12
12
  try {
13
13
  if (platform === 'win32') {
14
- const cmd = "powershell -command \"Get-CimInstance Win32_VideoController | Select-Object CurrentHorizontalResolution, CurrentVerticalResolution | Format-List\"";
15
- const output = execSync(cmd).toString();
14
+ const result = spawnSync("powershell", ["-command", "Get-CimInstance Win32_VideoController | Select-Object CurrentHorizontalResolution, CurrentVerticalResolution | Format-List"]);
15
+ if (result.error || result.status !== 0) throw new Error("Failed to execute powershell");
16
+ const output = result.stdout.toString();
16
17
  const width = output.match(/CurrentHorizontalResolution\s*:\s*(\d+)/)?.[1];
17
18
  const height = output.match(/CurrentVerticalResolution\s*:\s*(\d+)/)?.[1];
18
19
  return { width: parseInt(width), height: parseInt(height) };
19
20
  }
20
21
 
21
22
  if (platform === 'darwin') {
22
- const cmd = "system_profiler SPDisplaysDataType | grep Resolution";
23
- const output = execSync(cmd).toString();
23
+ const result = spawnSync("system_profiler", ["SPDisplaysDataType"]);
24
+ if (result.error || result.status !== 0) throw new Error("Failed to execute system_profiler");
25
+ const output = result.stdout.toString().split('\\n').filter(line => line.includes('Resolution')).join('\\n');
24
26
  const match = output.match(/(\d+) x (\d+)/);
25
27
  return { width: parseInt(match[1]), height: parseInt(match[2]) };
26
28
  }
package/tray.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const { app } = require("./index");
2
2
  const { Menu } = require("./menu");
3
+ const { warn } = require("./logs");
3
4
 
4
5
  let createdTray = false;
5
6
 
@@ -7,8 +8,10 @@ module.exports = {
7
8
 
8
9
  create(menu, title = "", icon = "") {
9
10
 
11
+ if(process.platform == "linux") return warn("Tray is not supported on Linux at this time.");
12
+
10
13
  if(createdTray) {
11
- console.warn("Tray already created. Use setMenu, setTitle, or setIcon to update the existing tray.");
14
+ warn("Tray already created. Use setMenu, setTitle, or setIcon to update the existing tray.");
12
15
  return;
13
16
  }
14
17
 
@@ -34,6 +37,9 @@ create(menu, title = "", icon = "") {
34
37
  },
35
38
 
36
39
  setMenu(menu) {
40
+
41
+ if(process.platform == "linux") return warn("Tray is not supported on Linux at this time.");
42
+
37
43
  if(menu instanceof Menu) {
38
44
  menu = menu.template
39
45
  }
@@ -54,10 +60,12 @@ create(menu, title = "", icon = "") {
54
60
  },
55
61
 
56
62
  setTitle(title) {
63
+ if(process.platform == "linux") return warn("Tray is not supported on Linux at this time.");
57
64
  app.sendToNative("createTray", [title, "setTitle"]);
58
65
  },
59
66
 
60
67
  setIcon(iconPath) {
68
+ if(process.platform == "linux") return warn("Tray is not supported on Linux at this time.");
61
69
  app.sendToNative("createTray", [iconPath, "setIcon"]);
62
70
  }
63
71